258 Lab アプリ開発日記

Andorid,iOSアプリ開発してます。

【Android】KotlinでRecyclerViewの無限スクロール

マイレビューは初期表示時、一度に全データをロードする処理だったが、 テスト的に大量データを登録したらロード時に時間がかかりこれはいかんと思い修正。。 対応策として、無限スクロールを採用した。

1. RecycleViewにスクロールイベントを追加

無限スクロールを実現するために、リストをスクロールし、末尾付近に差し掛かったら、データをロードする処理を追加。 まずはスクロールリスナーを追加する!今回はこちらを参考にさせて頂きました。

qiita.com

abstract class ScrollPageListener(layoutManager: LinearLayoutManager): RecyclerView.OnScrollListener() {

    private var mLayoutManager: LinearLayoutManager? = null
    private var mPage: Int = 0
    private var mPreTotalCount: Int = 0
    private var mIsLoading: Boolean = false
    private var visibleThreshold = 0

    init {
        mLayoutManager = layoutManager
    }

    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)
    }

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        // ロードするときに走るのは無駄なので、先にreturnする
        if (dx == 0 && dy == 0) {
            return
        }

        val visibleItemCount: Int = recyclerView.childCount
        val totalItemCount: Int = mLayoutManager!!.itemCount // グリッドの表示個数
        val firstVisibleItem: Int = mLayoutManager!!.findFirstVisibleItemPosition()

        if (mIsLoading) {
            if (totalItemCount > mPreTotalCount) {
                mIsLoading = false
                mPreTotalCount = totalItemCount
            }
        }

        if (!mIsLoading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            mIsLoading = true
            load(++mPage)
        }

    }

    abstract fun load(page: Int)

}

次にActivity側でRecycleViewのスクロールイベントにスクロールリスナーを設定する!

recycleView.addOnScrollListener(object: ScrollPageListener(reviewRecycleView.layoutManager as LinearLayoutManager) {
        override fun load(page: Int) {
                Log.d("scroll", "末尾だよ! $page")
                // ここでデータをロードする処理を追加!
        }
})

2. 末尾を検知し、データをロードした後の処理

末尾を検知したらデータをロード!ロードしたら、RecycleViewのアダプター側でデータを追加する! ここでつまずいた。。Adapterの「notifyItemRangeInserted」を実行しても行が追加されなかった。 色々調べると、データを追加し、Adapterで「notifyItemRangeInserted」を実行した後、 RecycleViewの「recycleView.scrollToPosition」を実行しないと行が追加されないみたい🐶

Activity側の処理

// ロードしたデータをAdapterに追加する(selectedReviewList→ロードしたデータのリスト)
reviewAdapter!!.addItem(selectedReviewList)
// ロードしているデータの末尾までスクロール(これをやらないとスクロールしないとデータが表示されない!)
recycleView.scrollToPosition(reviewRowList.size)

Adapter側の処理

    override fun getItemCount(): Int {
        // ・・・
    }

    @Override
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        // ・・・
    }

    @Override
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        // ・・・
    }

    /**
     * 行を追加する
     */
    fun addItem(reviewList: ArrayList<Review>) {

        val fromIdx = this.itemCount

        for (review in reviewList) {
            val idx = this.reviewList.indexOf(review)

            if (idx == -1) {
                this.reviewList.add(review)
            }
        }
       // ここでデータを追加されたことを通知!(通知しないと追加したデータが表示されない!)
        this.notifyItemRangeInserted(fromIdx, reviewList.size)
    }

リストって色々と考慮しないといけないなー🐈

マイレビューも是非インストールしてみてください!

play.google.com

今回は以上!