¡Guía simple de Paging3.0 de JetPack!

Autor: Chsmy

Hay un artículo sobre el uso y análisis de Paging2.x anterior. El efecto de Paging2.x ejecutando un deslizamiento infinito es bastante bueno, pero el código es un poco complicado de escribir y la función no es demasiado perfecta. Por ejemplo, el No se proporciona el método de actualización desplegable, tenemos que llamar al método DataSource # invalidate () para restablecer los datos usted mismo. Recientemente, Google lanzó la versión beta de 3.0, que es más potente y más fácil de usar. Probémosla ahora.

Primero mire la introducción del sitio web oficial a Paging3.0

  • Los datos de paginación se almacenan en caché en la memoria para garantizar que las aplicaciones utilicen los recursos del sistema de manera más eficaz al procesar los datos de la página.
  • Al mismo tiempo, varias solicitudes idénticas solo activarán una, lo que garantiza que la aplicación use los recursos de red y los recursos del sistema de manera efectiva
  • Puede configurar los adaptadores de RecyclerView para iniciar automáticamente solicitudes cuando se desliza hasta el final
  • Buen soporte para Coroutine Kotlin y Flow, LiveData, RxJava
  • Actualización, reintento, manejo de errores y otras funciones integradas

Para comenzar a usar, primero introduzca las bibliotecas dependientes

def paging_version = "3.0.0-alpha02"
implementation "androidx.paging:paging-runtime:$paging_version"

Para configurar un RecyclerView, hay dos partes principales: una es el Adaptador y la otra son los datos. Comience con el adaptador

Adaptador de compilación

La creación de Adapter es similar a Paging2.x, pero la clase heredada es diferente. Paging2.x hereda PagedListAdapter. En 3.0, PagedListAdapter ya no está disponible y necesita heredar PagingDataAdapter.

class ArticleAdapter : PagingDataAdapter<Article,ArticleViewHolder>(POST_COMPARATOR){

    companion object{
        val POST_COMPARATOR = object : DiffUtil.ItemCallback<Article>() {
            override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean =
                    oldItem == newItem

            override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean =
                    oldItem.id == newItem.id
        }
    }

    override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
         holder.tvName.text = getItem(position)?.title
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
        return ArticleViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item,parent,false))
    }

}
class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
   val tvName: TextView = itemView.findViewById(R.id.tvname)
}

El método de escritura es básicamente el mismo que el RecyclerView.Adapter normal, con una cosa añadida, es necesario pasar un DiffUtil.ItemCallback en el constructor para determinar la regla de cálculo cuando se actualiza la diferencia.

El adaptador está terminado, los siguientes son los datos, usamos la rutina de reequipamiento y Kotlin para obtener los datos de la red y configurar los datos en el adaptador

Obtenga datos y configúrelos en Adaptador

Desde el sitio web oficial, Google recomienda que use una arquitectura de tres niveles para completar los datos en la configuración del Adaptador, como la siguiente figura en el sitio web oficial

La primera capa del repositorio de la capa del almacén de datos

La capa Repository se implementa principalmente mediante el componente de paginación de PagingSource. Cada objeto PagingSource corresponde a una fuente de datos y cómo encontrar datos de la fuente de datos. PagingSource puede encontrar datos de cualquier fuente de datos única, como la red o la base de datos.

La capa de repositorio tiene otro componente de paginación que puede usar RemoteMediator, que es una fuente de datos jerárquica, como una fuente de datos de red con una caché de base de datos local.

Cree nuestro PagingSource y Repository a continuación

class ArticleDataSource:PagingSource<Int,Article>() {

    /**
     * 实现这个方法来触发异步加载(例如从数据库或网络)。 这是一个suspend挂起函数,可以很方便的使用协程异步加载
     */
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Article> {

        return try {
            val page = params.key?:0
            //获取网络数据
            val result = WanRetrofitClient.service.getHomeList(page)
            LoadResult.Page(
                    //需要加载的数据
                    data = result.data.datas,
                    //如果可以往上加载更多就设置该参数,否则不设置
                    prevKey = null,
                    //加载下一页的key 如果传null就说明到底了
                    nextKey = if(result.data.curPage==result.data.pageCount) null else page+1
            )
        }catch (e:Exception){
            LoadResult.Error(e)
        }

    }
}
  • La herencia de PagingSource requiere dos tipos genéricos. El primero representa el método de carga de la siguiente página de datos. Por ejemplo, usar el número de página para cargar puede pasar Int, usar un determinado atributo del último dato para cargar la página siguiente y pasar otros tipos como String, etc.
  • Implemente su método de carga para activar la carga asincrónica, puede ver que es una función de suspensión decorada con suspender, que se puede cargar fácilmente con una rutina de forma asincrónica.
  • Hay un valor clave en el parámetro LoadParams, que podemos usar para cargar la página siguiente.
  • El valor de retorno es un LoadResult. Si ocurre una excepción, se llama a LoadResult.Error (e) y se llama al método LoadResult.Page en la apertura forzada normal para configurar los datos obtenidos de la red o base de datos.
  • prevKey y nextKey respectivamente representan el factor de carga que debe proporcionarse cuando se carga hacia arriba o hacia abajo la próxima vez. Por ejemplo, cuando cargamos los datos de cada página a través del aumento continuo de la página, nextKey se puede pasar a la página siguiente + 1 . Si se establece en nulo, no hay datos.

Crear repositorio

class ArticleRepository {

    fun getArticleData() = Pager(PagingConfig(pageSize = 20)){
        ArticleDataSource()
    }.flow

}

El código es pequeño pero hay dos objetos importantes: Pager y PagingData

  • Pager es la entrada principal a la paginación, requiere 4 parámetros: PagingConfig, Key, RemoteMediator, PagingSource, el primero y el cuarto de los cuales son obligatorios.
  • PagingConfig se usa para configurar algunos atributos al cargar, como cuántos elementos se cuentan como una página, qué tan lejos de la parte inferior para comenzar a cargar la página siguiente, el número de elementos cargados inicialmente, etc.
  • PagingData se utiliza para almacenar los resultados de cada adquisición de datos de paginación
  • Flow es el flujo de datos asincrónico de Kotlin, similar al Observable de RxJava

Segunda capa ViewModel

El repositorio finalmente devuelve un paquete de flujo asíncrono PagingDataFlow <PagingData>, PagingData almacena los resultados de los datos y, finalmente, puede usarlo para asociar los datos con la interfaz de IU.

LiveData se usa generalmente en ViewModel para interactuar con la capa de la interfaz de usuario, y la función de extensión de Flow se puede convertir directamente en un objeto observable LiveData.

class PagingViewModel:ViewModel() {

    private val repository:ArticleRepository by lazy { ArticleRepository() }
    /**
     * Pager 分页入口 每个PagingData代表一页数据 最后调用asLiveData将结果转化为一个可监听的LiveData
     */
    fun getArticleData() = repository.getArticleData().asLiveData()

}

Capas de UI

La capa de interfaz de usuario está en realidad en nuestra actividad, configure el adaptador para RecycleView, configure los datos para Adater

class PagingActivity : AppCompatActivity() {

    private val viewModel by lazy { ViewModelProvider(this).get(PagingViewModel::class.java) }

    private val adapter: ArticleAdapter by lazy { ArticleAdapter() }

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

        val refreshView:SmartRefreshLayout = findViewById(R.id.refreshView)
        val recyclerView :RecyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter.withLoadStateFooter(PostsLoadStateAdapter(adapter))
        //获取数据并渲染UI
        viewModel.getArticleData().observe(this, Observer {
            lifecycleScope.launchWhenCreated {
                adapter.submitData(it)
            }
        })
        //监听刷新状态当刷新完成之后关闭刷新
        lifecycleScope.launchWhenCreated {
            @OptIn(ExperimentalCoroutinesApi::class)
            adapter.loadStateFlow.collectLatest {
                if(it.refresh !is LoadState.Loading){
                    refreshView.finishRefresh()
                }
            }
        }
        refreshView.setOnRefreshListener {
            adapter.refresh()
        }
    }
}
  • Cree una instancia del adaptador escrito anteriormente y configúrelo en RecyclerView
  • Llame al método viewModel.getArticleData () para obtener LiveData y monitorear los datos devueltos
  • Llame al método submitData del adaptador para activar la representación de la página. Este método es un método de suspensión modificado suspendido, por lo que se llama en una corrutina con un ciclo de vida. Si no desea ponerlo en la corrutina, puede llamar a otro método de dos parámetros adapter.submitData (ciclo de vida, it) y pasarlo a ciclo de vida.

Actualizar y volver a intentar

El método de llamar a la actualización en Paging3.0 es mucho más conveniente que en Paging2.x. Proporciona directamente un método de actualización y también proporciona un método de reintento después de cargar un error de datos.

En el código de actividad anterior, el método adapter.refresh () se puede llamar directamente en el monitor desplegable del control de actualización desplegable para completar la actualización. Cuando cierre la animación de actualización, debe llamar al adaptador.loadStateFlow .collectLatest método para monitorear

 lifecycleScope.launchWhenCreated {
            @OptIn(ExperimentalCoroutinesApi::class)
            adapter.loadStateFlow.collectLatest {
                if(it.refresh !is LoadState.Loading){
                    refreshView.finishRefresh()
                }
            }
        }

El estado del flujo de recopilación, si no es el estado Cargando, la carga está completa, puede cerrar la animación.

PagingDataAdapter puede establecer el progreso de carga del cabezal y la parte inferior o el diseño cuando se produce un error de carga, de modo que cuando está en el estado de carga, se puede mostrar la animación de carga y se puede mostrar el botón de reintento cuando se produce el error de carga. También es simple y cómodo de usar.

Debe personalizar un adaptador para heredar de LoadStateAdapter y configurar este adaptador en el adaptador inicial.

class PostsLoadStateAdapter(
        private val adapter: ArticleAdapter
) : LoadStateAdapter<NetworkStateItemViewHolder>() {
    override fun onBindViewHolder(holder: NetworkStateItemViewHolder, loadState: LoadState) {
        holder.bindTo(loadState)
    }

    override fun onCreateViewHolder(
            parent: ViewGroup,
            loadState: LoadState
    ): NetworkStateItemViewHolder {
        return NetworkStateItemViewHolder(parent) { adapter.retry() }
    }
}

ViewHolder

class NetworkStateItemViewHolder(
    parent: ViewGroup,
    private val retryCallback: () -> Unit
) : RecyclerView.ViewHolder(
    LayoutInflater.from(parent.context).inflate(R.layout.network_state_item, parent, false)
) {
    private val progressBar = itemView.findViewById<ProgressBar>(R.id.progress_bar)
    private val errorMsg = itemView.findViewById<TextView>(R.id.error_msg)
    private val retry = itemView.findViewById<Button>(R.id.retry_button)
        .also {
            it.setOnClickListener { retryCallback() }
        }

    fun bindTo(loadState: LoadState) {
        progressBar.isVisible = loadState is Loading
        retry.isVisible = loadState is Error
        errorMsg.isVisible = !(loadState as? Error)?.error?.message.isNullOrBlank()
        errorMsg.text = (loadState as? Error)?.error?.message
    }
}

Hay tres tipos de LoadState: NotLoading, Loading, Error, podemos cambiar el estilo de diseño en la parte inferior o superior según los diferentes estados

Finalmente establecido en la actividad, agregue un diseño inferior a continuación

recyclerView.adapter = adapter.withLoadStateFooter(PostsLoadStateAdapter(adapter))

Simplemente llame directamente a los métodos relevantes del adaptador, hay tres métodos en total, agregue la parte inferior, agregue el encabezado y agregue ambos.

El simple uso de Paging3.0 ha logrado los siguientes efectos:

Si está más interesado en las nuevas tecnologías, preste atención a este número y publicaremos artículos prácticos más detallados más adelante.

La mayoría. La mayoría. La mayoría. Finalmente, aquí también comparto el PDF de aprendizaje de Android que he recopilado y organizado. Hay una explicación detallada de Jetpack. Espero que pueda ayudarte a aprender a mejorar y ahorrarte tiempo buscando materiales en Internet. Puede compartir con amigos a su alrededor para aprender juntos

Si lo necesitas, puedes  conseguirlo aquí

Supongo que te gusta

Origin blog.csdn.net/River_ly/article/details/107073014
Recomendado
Clasificación