Utilisation d'Android Jetpack - Paging2.0

 

     Google déploie la composante Jetpack depuis un certain temps. Divers composants émergent également à l'infini.

     Jetpack a aussi beaucoup de choses,

    

 

     Faites cette   pagination aujourd'hui

     L'émergence de la pagination est utilisée pour la pagination du chargement des listes. En fait, il existe déjà de nombreux contrôles de chargement de liste open source matures et efficaces, tels que : Smartrefreshlayout , etc. Mais ce que Google a lancé doit avoir ses avantages, et bien sûr ses limites.

     Parlons d'abord des avantages. L'utilisation de Paging doit coopérer avec des contrôles tels que ViewModle et LiveData. La demande de données détecte et lie le cycle de vie de la page pour éviter les fuites de mémoire. Il est également nécessaire de lier la DataSource et la Factory de la DataSource, qui peuvent charger plus de données sans trace et améliorer l'expérience utilisateur dans une certaine mesure.

 

    Le processus principal est :

     1 : Personnalisez PositionalDataSource, la fonction à l'intérieur consiste à demander la pagination des données.

     2 : Personnalisez DataSource.Factory, liez PositionalDataSource à LiveData

     3 : L'activité personnalise ViewModel, lie PositionalDataSource et Factory, et permet à ViewModel de percevoir les modifications de données 

     4 : ViewModel perçoit les modifications de données et met à jour la submitList de PagedListAdapter.

Examinez d'abord l'importation de ces dépendances :

    implementation "androidx.paging:paging-runtime:2.0.0"
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation "android.arch.lifecycle:extensions:1.1.1"

 

【1】Regardez d'abord le code d'activité :

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val myPagedListAdapter = MyPagedListAdapter()
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = myPagedListAdapter

        /**
         *      ViewModel 绑定 Activity 生命周期
         * */
        val myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)

        /**
         *      ViewModel 感知数据变化,更新 Adapter 列表
         * */
        myViewModel.getConvertList().observe(this, Observer {
            myPagedListAdapter.submitList(it)
        })
    }

}

 

[2] Regardez le code de l'adaptateur :

Le PagedListAdapter              est utilisé ici En fait, il hérite du RecyclerView.Adapter , il n'est donc pas très différent du RecyclerView.Adapter utilisé , mais il existe un besoin interne supplémentaire pour implémenter DiffUtil.ItemCallback . Le principe spécifique de DiffUtil.ItemCallback n'est pas évoqué ici, et le blogueur ne l'a pas étudié en détail, il sert à comparer des données. Sa méthode de mise en œuvre interne peut fondamentalement être écrite à mort.

class MyPagedListAdapter extends PagedListAdapter<MyDataBean, MyViewHolder> {


    private static DiffUtil.ItemCallback<MyDataBean> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<MyDataBean>() {
                @Override
                public boolean areItemsTheSame(MyDataBean oldConcert, MyDataBean newConcert) {
                    // 比较两个Item数据是否一样的,可以简单用 Bean 的 hashCode来对比
                    return oldConcert.hashCode() == newConcert.hashCode();
                }

                @Override
                public boolean areContentsTheSame(MyDataBean oldConcert,
                                                  MyDataBean newConcert) {
                    // 写法基本上都这样写死即可
                    return oldConcert.equals(newConcert);
                }
            };

    
    public MyPagedListAdapter() {
        // 通过 构造方法 设置 DiffUtil.ItemCallback 
        super(DIFF_CALLBACK);
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_my, parent, false);
        return new MyViewHolder(inflate);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        // getItem() 是 PagedListAdapter 内部方法,通过此方法可以获取到对应位置Item 的数据
        holder.bindData(getItem(position));
    }

}
 
 

Au fait, collez également ViewHolder et MyDataBean

ViewHolder :

class MyViewHolder(val itemV: View) : RecyclerView.ViewHolder(itemV) {

    fun bindData(data: MyDataBean) {
        itemV.findViewById<TextView>(R.id.tvNum).text = data.position.toString()

        if (data.position % 2 == 0){
            itemV.findViewById<TextView>(R.id.tvNum).setBackgroundColor(itemV.context.resources.getColor(R.color.colorAccent))
        }else{
            itemV.findViewById<TextView>(R.id.tvNum).setBackgroundColor(itemV.context.resources.getColor(R.color.colorPrimaryDark))
        }
    }
}

MyDataBean :

data class MyDataBean(val position: Int)

 

[3] Regardez le code DataSource :

PositionalDataSource, la fonction à l'intérieur est de demander la pagination des données.

Deux méthodes sont à mettre en place :

loadInitial() : Lorsque la page est ouverte pour la première fois, cette méthode doit être rappelée pour obtenir des données

loadRange () :   une fois les données d'initialisation disponibles, cette méthode sera appelée si les données doivent être chargées lors du glissement.

class MyDataSource : PositionalDataSource<MyDataBean>() {

    /**
     *  第一次打开页面,需要回调此方法来获取数据
     * */
    override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<MyDataBean>) {
        // 获取网络数据
        val list = getData(params.requestedStartPosition, params.pageSize)
        /**
         *      这个方法是返回数据,让 绑定ViewModel 感知。 这里要用对方法
         *      @param1  数据列表
         *      @param2  数据为起始位置
         *      @param3  数据列表总长度,这个一定要设置好哦,如果设置了50,
         *               当列表的长度为50时,列表再也无法出发 loadRange() 去加载更多了
         *               如果不知道列表总长度,可以设置 Int 的最大值 999999999
         *               这里设置 10000
         * */
        callback.onResult(list, 0, 10000)
    }

    /**
     *  当有了初始化数据之后,滑动的时候如果需要加载数据的话,会调用此方法。
     * */
    override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<MyDataBean>) {
        /**
         *      params.startPosition  列表需要从 startPosition 加载更多
         *      params.loadSize       列表需要从 startPosition 加载长度 为 loadSize的数据
         * */
        val list = getData(params.startPosition, params.loadSize)
        callback.onResult(list)
    }

    /**
     *  模拟网络获取数据
     * */
    private fun getData(startPosition: Int, pageSize: Int): MutableList<MyDataBean> {

        
        Handler(Looper.getMainLooper()).post {
            Toast.makeText(
                MyApplication.instant,
                "加载数据 从 $startPosition 加载到 ${startPosition + pageSize}",
                Toast.LENGTH_SHORT
            ).show()
        }

        val list = mutableListOf<MyDataBean>()
        for (i in startPosition until startPosition + pageSize) {
            list.add(MyDataBean(i))
        }
        return list
    }
}

 

[4] Regardez le code DataSource.Factory :

Lier PositionalDataSource à LiveData

class DataFactory: DataSource.Factory<Int, MyDataBean>() {

    private val mSourceLiveData: MutableLiveData<MyDataSource> =
        MutableLiveData<MyDataSource>()

    override fun create(): DataSource<Int, MyDataBean> {
        val myDataSource = MyDataSource()
        mSourceLiveData.postValue(myDataSource)
        return myDataSource
    }

}

 

[5] Enfin, regardez le code ViewModel :

class MyViewModel : ViewModel() {

    private var mDataSource : DataSource<Int, MyDataBean>
    private var mDataList: LiveData<PagedList<MyDataBean>>

    init {
        // 把 PositionalDataSource 和 Factory 绑定,让 ViewModel 感知数据的变化
        var dataFactory = DataFactory()
        mDataSource = dataFactory.create()
        /**
         *      @param1 dataFactory 设定 dataFactory
         *      @param2 设定每一次加载的长度 
         *              这个和 PositionalDataSource 回调方法 loadSize 一致的
         * */ 
        mDataList = LivePagedListBuilder(dataFactory, 20).build()
    }

    // 暴露方法,让Activity 感知数据变化,去驱动 Adapter更新列表
    fun getConvertList(): LiveData<PagedList<MyDataBean>> {
        return mDataList
    }
}

[5] Enfin, regardez le code d'activité :

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val myPagedListAdapter = MyPagedListAdapter()
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = myPagedListAdapter

        /**
         *      ViewModel 绑定 Activity 生命周期
         * */
        val myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)

        /**
         *      ViewModel 感知数据变化,更新 Adapter 列表
         * */
        myViewModel.getConvertList().observe(this, Observer {
            myPagedListAdapter.submitList(it)
        })
    }

}

Collez le code de activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">
    </androidx.recyclerview.widget.RecyclerView>

</androidx.constraintlayout.widget.ConstraintLayout>

Exécutez-le pour voir l'effet :

Il fonctionne avec succès sans aucun problème.

 

Au début, j'ai dit que la pagination avait des inconvénients, en fait, la pagination n'a pas de rafraîchissement déroulant, seulement un pull-up pour charger plus de fonctions. Ce n'est pas suffisant pour de nombreuses occasions d'inscription.

Mais si vous avez seulement besoin de tirer et de charger plus, la pagination est toujours recommandée, après tout, elle est fournie par Google.

 

Il n'y a aucun problème avec le test de code ci-dessus, veuillez laisser un message si vous avez des questions.

 

Adresse du code : https://github.com/LeoLiang23/PagingDemo.git

Je suppose que tu aimes

Origine blog.csdn.net/Leo_Liang_jie/article/details/109473099
conseillé
Classement