web-dev-qa-db-ja.com

ページングライブラリとPositionalDataSourceを使用してRecyclerViewが空のままになる

Androidページングライブラリをプロジェクトのページングライブラリに設定して、メッセージのページ付けされたリストをRecyclerViewにロードしようとしています。APIはオフセットと最大値を使用するため、PositionalDataSourceを使用しています。

これが私のDataSource実装です。DataStoreがRetroFitを使用してメッセージをロードしています。コンソールでメッセージが適切にロードされ、MessageListItemのインスタンスに変換されていることがわかります。

_class MessageDataSource: PositionalDataSource<MessageListItem>() {
    override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<MessageListItem>) {
        DataStore.shared.loadMessages(params.startPosition, params.loadSize) { result, error ->
            if(result != null) {
                callback.onResult(result.items)
            } else {
                callback.onError(MessageDataSourceException(error))
            }
        }
    }

    override fun loadInitial(
        params: LoadInitialParams,
        callback: LoadInitialCallback<MessageListItem>
    ) {
        DataStore.shared.loadMessages(params.requestedStartPosition, params.requestedLoadSize) { response, error ->
            if(response != null) {
                callback.onResult(response.items, response.offset, response.total)
            } else {
                callback.onError(MessageDataSourceException(error))
            }
        }
    }
}

class MessageDataSourceException(rootCause: Throwable? = null): Exception(rootCause)
_

これが私のDataSourceFactory実装です:

_class MessageDataSourceFactory: DataSource.Factory<Int, MessageListItem>() {
    val messageLiveDataSource = MutableLiveData<MessageDataSource>()
    private lateinit var messageDataSource: MessageDataSource

    override fun create(): DataSource<Int, MessageListItem> {
        messageDataSource = MessageDataSource()
        messageLiveDataSource.postValue(messageDataSource)
        return messageDataSource
    }
}
_

これが私のMessageListAdapter実装です:

_object MessageListItemDiff: DiffUtil.ItemCallback<MessageListItem>() {
    override fun areItemsTheSame(oldItem: MessageListItem, newItem: MessageListItem): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: MessageListItem, newItem: MessageListItem): Boolean {
        return oldItem == newItem
    }
}

class MessageListAdapter(private val clickListener: View.OnClickListener):
    PagedListAdapter<MessageListItem, MessageListAdapter.MessageHolder>(MessageListItemDiff) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageHolder {
        val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.item_message, parent, false)
        return MessageHolder(inflatedView, clickListener)
    }

    override fun onBindViewHolder(holder: MessageHolder, position: Int) {
        holder.bind(getItem(position)!!)
    }

    class MessageHolder(itemView: View, private val clickListener: View.OnClickListener) : RecyclerView.ViewHolder(itemView) {
        val unreadIndicator = itemView.findViewById<ImageView>(R.id.unreadIndicator)
        val title = itemView.findViewById<TextView>(R.id.title)
        val dateSent = itemView.findViewById<TextView>(R.id.dateSent)
        val cardView = itemView.findViewById<CardView>(R.id.card_view)

        fun bind(message: MessageListItem) {
            cardView.tag = message
            cardView.setOnClickListener(clickListener)
            title.text = message.title
            dateSent.text = TimeAgo.using(message.dateSent.time)
            if(message.isRead) {
                unreadIndicator.setImageResource(0)
            } else {
                unreadIndicator.setImageResource(R.drawable.ic_unread)
            }
        }
    }
}
_

そして最後に私のViewModel:

_class MessageListViewModel: ViewModel() {
    val messagePagedList: LiveData<PagedList<MessageListItem>>
    val liveDataSource: LiveData<MessageDataSource>

    init {
        val messageDataSourceFactory = MessageDataSourceFactory()
        liveDataSource = messageDataSourceFactory.messageLiveDataSource

        val pagedListConfig = PagedList.Config.Builder()
            .setEnablePlaceholders(false)
            .setPageSize(30)
            .setPrefetchDistance(90)
            .build()
        messagePagedList = LivePagedListBuilder(messageDataSourceFactory, pagedListConfig).build()
    }
}
_

そして、これは、messageListというリサイクラービューを表示することになっているフラグメントのonViewCreated実装です。

_override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        messageList.layoutManager = LinearLayoutManager(context!!)
        messageList.setHasFixedSize(true)

        messageListViewModel = ViewModelProvider(this).get(MessageListViewModel::class.Java)
        messageListAdapter = MessageListAdapter(this)

        messageListViewModel.messagePagedList.observe(this, Observer { messages ->
            messageListAdapter.submitList(messages)
        })

        messageList.adapter = messageListAdapter
    }
_

問題は、サーバーからデータが読み込まれていることは確認できますが、リサイクラービューに到達しないことです。オブザーバーの行(messageListAdapter.submitList(messages))にブレークポイントを追加すると、メッセージリストが空の呼び出しが1回取得されます。

私はこれらすべてのクラスとそれらが何をすべきかと本当に混乱していることを認めなければなりません、これはAndroidでの最初のページング実装であり、使用したくなかったので、私はあちこちで見つけたコードを適応させなければなりませんでしたRoomデータベース、RxJavaまたはPageKeyedDataSource。ほとんどのサンプルで使用されています。

何が起こっているのでしょうか?

5
Sebastien

これを変える:

messageListViewModel.messagePagedList.observe(this, Observer { messages ->
    messageListAdapter.submitList(messages)
})

これとともに:

messageListViewModel.messagePagedList.observe(viewLifeCycleOwner, PagedList(messageListAdapter::submitList))

ソース: https://developer.Android.com/topic/libraries/architecture/paging#ex-observe-livedata

0
Harry Timothy

新しいデータの監視の実装とページングライブラリの実装にいくつかの問題があります。

この記事を使用して、すべてのステップを簡単に実行してください。ここではすべてのクラスが私には不可能なので、ここにあなたの問題の解決策があります: https://www.simplifiedcoding.net/Android-paging-library-tutorial/

0
Abhishek Garg