În acest tutorial, vă vom arăta cum să utilizați biblioteca Paging din Componentele Android Architecture cu o bază de date bazată pe cameră într-o aplicație Android.
Veți învăța cum să utilizați biblioteca de pagini pentru a încărca în mod eficient seturi mari de date dintr-o bază de date bazată pe cameră, oferind utilizatorilor o experiență mai bună în timp ce derulați într-un RecyclerView.
Pentru a putea urma acest tutorial, veți avea nevoie de:
LiveData
și baza de date a camerei)Dacă nu ați învățat despre componentele de arhitectură, vă recomandăm să consultați seria noastră minunată despre toate componentele Android Architecture by Tin Megali. Asigurați-vă că vă plimbați!
Un exemplu de proiect pentru acest tutorial poate fi găsit pe replica noastră GitHub, pentru a putea urmări cu ușurință.
Biblioteca de paginare este o altă bibliotecă adăugată componentelor de arhitectură. Biblioteca ajută în mod eficient la încărcarea și afișarea unui set mare de date în RecyclerView
. Potrivit documentelor oficiale:
Biblioteca de pagini vă ușurează încărcarea treptată și grațios a datelor în aplicațiile dvs.RecyclerView
.
Dacă o parte a aplicației dvs. Android va afișa un set de date mare dintr-o sursă de date locală sau la distanță, dar va afișa doar o parte din ea la un moment dat, atunci ar trebui să luați în considerare utilizarea bibliotecii Paging. Acest lucru vă va ajuta să îmbunătățiți performanța aplicației!
Acum că ați văzut o introducere în biblioteca Paging, ați putea întreba, de ce să o utilizați? Iată câteva motive pentru care ar trebui să luați în considerare utilizarea acestuia la încărcarea seturilor de date mari într-un RecyclerView
.
Nu va fi eficient atunci când lucrați cu o cantitate mare de date, deoarece sursa de date subiacentă preia toate datele, deși numai un subset al acestor date va fi afișat utilizatorului. Într-o astfel de situație, ar trebui să luăm în considerare paginarea datelor.
Activați Android Studio 3 și creați un nou proiect cu o activitate goală numită Activitate principala
. Asigurați-vă că ați verificat Includeți suportul Kotlin.
După ce ați creat un nou proiect, adăugați următoarele dependențe în build.gradle. În acest tutorial, folosim ultima versiune 1.0.1 a bibliotecii Paging, în timp ce Camera este 1.1.1 (începând cu această scriere).
dependencies implementare fileTree (dir: 'libs', include: ['* .jar']) implementare "android.arch.persistence.room:runtime:1.1.1" kapt "android.arch.persistence.room:compiler:1.1 .1 "implementare" android.arch.paging: runtime: 1.0.1 "implementare" com.android.support:recyclerview-v7:27.1.1 "
Aceste artefacte sunt disponibile la depozitul Google Maven.
toate proiectele repositories google () jcenter ()
Prin adăugarea dependențelor, l-am învățat pe Gradle cum să găsească biblioteca. Asigurați-vă că vă amintiți să vă sincronizați proiectul după ce le-ați adăugat.
Creați o nouă clasă de date Kotlin Persoană
. Din simplitate, ale noastre Persoană
entitatea are doar două domenii:
id
)Nume
)În plus, includeți a toString (
care returnează pur și simplu Nume
.
(nume_primarKey val id: String, nume val: String) suprascris fun toString ( ) = nume
După cum știți, pentru a accesa datele aplicației noastre în biblioteca de cameră, avem nevoie de obiecte de acces la date (DAO). În cazul nostru, am creat o PersonDao
.
importați android.arch.lifecycle.LiveData importați android.arch.paging.DataSource importați android.arch.persistence.room.Dao import android.arch.persistence.room.Delete de import android.arch.persistence.room.Insert import android.arch .persistence.room.Query @Dao interfață PersonDao @Query ("SELECT * FROM people") distracție getAll (): LiveData> @Query ("SELECT * FROM persons") distracție getAllPaged (): DataSource.Factory
@ Introduceți distracție inserați (Persoane: Listă ) @ Șterge distracția șterge (persoană: Persoană)
În a noastră PersonDao
clasa, avem două @Query
metode. Unul dintre ei este ia tot()
, care returnează a LiveData
care deține o listă de Persoană
obiecte. Celălalt este getAllPaged ()
, care returnează a DataSource.Factory
.
Conform documentelor oficiale, Sursă de date
clasa este:
Clasa de bază pentru încărcarea paginilor de date instantanee într-un PagedList
.
A PagedList
este un tip special de Listă
pentru afișarea datelor pagerate în Android:
APagedList
este o listă care încarcă datele sale în bucăți (pagini) de laSursă de date
. Elementele pot fi accesate cuget (int)
, iar încărcarea ulterioară poate fi declanșată culoadAround (int)
.
Am sunat Fabrică
metoda statică în Sursă de date
clasa, care servește ca o fabrică (crearea de obiecte fără a fi nevoie să precizeze clasa exactă a obiectului care va fi creat) pentru Sursă de date
. Această metodă statică are două tipuri de date:
Sursă de date
. Rețineți că pentru o interogare Cameră, paginile sunt numerotate - așa că vom folosi Întreg
ca tip de identificator al paginii. Este posibil să aveți pagini "cheie" folosind Biblioteca de pagini, dar Camera nu oferă în prezent. Sursă de date
s.Iata ce inseamna clasa bazei de date Room AppDatabase
se pare ca:
importați android.arch.persistence.db.SupportSQLiteDatabase import șiroid.arch.persistence.room.Data de import android.arch.persistence.room.Room de import android.arch.persistence.room.RoomDatabase de import android.content.Context import androidx.work .OneTimeWorkRequestBuilder importați androidx.work.WorkManager import com.chikeandroid.pagingtutsplus.utils.DATABASE_NAME import com.chikeandroid.pagingtutsplus.workers.SeedDatabaseWorker @Database (entities = [Person :: class], version = 1, exportSchema = false) clasă abstractă Aplicația bazei de date: RoomDatabase () abstract persona distracțieDao (): Obiect de persoană personalizată Dada // Pentru instanțierea Singleton @Volatile private instance instance: AppDatabase? = null distracție getInstance (context: Context): AppDatabase instanța retur?: sincronizată (aceasta) instance?: buildDatabase (context) .also instance = it .databaseBuilder (context, AppDatabase :: class.java, DATABASE_NAME) .addCallback (obiect: RoomDatabase.Callback () suprascris fun onCreate (db: SuportSQLiteDatabase) super.onCreate (db) val request = OneTimeWorkRequestBuilder()) .build () WorkManager.getInstance () ?. enqueue (cerere)) .build ()
Aici am creat o singură instanță a bazei noastre de date și l-am prefolosit cu date folosind noul WorkManager API. Rețineți că datele pre-populate sunt doar o listă cu 1000 de nume (se aruncă în codul sursă de probă furnizat pentru a afla mai multe).
Pentru ca UI-ul nostru să stocheze, să observe și să servească date în mod conștient, avem nevoie de a ViewModel
. Al nostru PersonsViewModel
, care extinde AndroidViewModel
clasa, va funcționa ca și noi ViewModel
.
importați android.app.Application import șiroid.arch.lifecycle.AndroidViewModel import android.arch.lifecycle.LiveData import android.arch.paging.DataSource import android.arch.paging.LivePagedListBuilder import android.arch.paging.PagedList import com.chikeandroid .pagingtutsplus.data.AppDatabase import com.chikeandroid.pagingtutsplus.data.Person clasa PersonsViewModel constructor (aplicatie: aplicatie): AndroidViewModel (aplicatie) private var peopleLiveData: LiveData> init fabrică val: DataSource.Factory = AppDatabase.getInstance (getApplication ()). PersoanăDao (). GetAllPaged () val pagedListBuilder: LivePagedListBuilder = LivePagedListBuilder (fabrică, 50) peopleLiveData = pagedListBuilder.build () distracție getPersonsLiveData () = personsLiveData
În această clasă, avem un singur câmp numit personsLiveData
. Acest câmp este pur și simplu a LiveData
care deține a PagedList
de Persoană
obiecte. Pentru că asta este a LiveData
, interfața noastră utilizator Activitate
sau Fragment
) va observa aceste date apelând metoda getter getPersonsLiveData ()
.
Am inițializat personsLiveData
în interiorul init
bloc. În interiorul acestui bloc, obținem DataSource.Factory
prin apelarea AppDatabase
singleton pentru PersonDao
obiect. Când obținem acest obiect, sunăm getAllPaged ()
.
Apoi creăm un LivePagedListBuilder
. Iată ce spune în documentația oficială despre a LivePagedListBuilder
:
Builder pentruLiveData
, dat fiind aDataSource.Factory
și aPagedList.Config
.
Furnizăm constructorul său a DataSource.Factory
ca primul argument și dimensiunea paginii ca al doilea argument (în cazul nostru, dimensiunea paginii va fi de 50). De obicei, ar trebui să alegeți o dimensiune care să fie mai mare decât numărul maxim pe care îl puteți afișa simultan utilizatorului. În cele din urmă, sunăm construi()
să ne construim și să ne întoarcem a LiveData
.
Pentru a ne arăta PagedList
date într-un RecyclerView
, avem nevoie de PagedListAdapter
. Iată o definiție clară a acestei clase din documentele oficiale:
RecyclerView.Adapter
clasa de bază pentru prezentarea datelor paginate de laPagedList
s într-oRecyclerView
.
Așa că noi creăm a PersonAdapter
care se extinde PagedListAdapter
.
importați android.arch.paging.PagedListAdapter importați android.content.Context importați android.support.v7.widget.RecyclerView importați android.view.LayoutInflater import android.view.Video import import android.view.ViewGroup import android.widget.TextView import com .chikeandroid.pagingtutsplus.R import com.chikeandroid.pagingtutsplus.data.Person import kotlinx.android.synthetic.main.item_person.view. * class PersonAdapter (val context: Context): PagedListAdapter(PersonDiffCallback ()) suprascrie distracția onBindViewHolder (holderPerson: PersonViewHolder, position: Int) var person = getItem (poziție) if (person == null) holderPerson.clear () else holderPerson.bind (person) suprascrie distracția onCreateViewHolder (parentă: ViewGroup, viewType: Int): PersonViewHolder retur PersonViewHolder (LayoutInflater.from (context) .inflate (R.layout.item_person, parent, false) class PersonViewHolder (vizualizare: View): RecyclerView.ViewHolder (vizualizare) var tvName: TextView = nume de viziune funny (persoană: Persoană) tvName.text = person.name fun clear () tvName.text = null
PagedListAdapter
este folosit la fel ca orice altă subclasă de RecyclerView.Adapter
. Cu alte cuvinte, trebuie să implementați metodele onCreateViewHolder ()
și onBindViewHolder ()
.
Pentru a extinde PagedListAdapter
clasa abstractă, va trebui să furnizați - în constructorul său - tipul de PageLists
(aceasta ar trebui să fie o clasă veche clasică Java: un POJO) și, de asemenea, o clasă care extinde ViewHolder
care vor fi utilizate de adaptor. În cazul nostru, l-am dat Persoană
și PersonViewHolder
ca prim și, respectiv, al doilea argument.
Rețineți că PagedListAdapter
cere să-i dai o a DiffUtil.ItemCallback
la PageListAdapter
constructor. DiffUtil
este a RecyclerView
clasa de utilități care poate calcula diferența dintre două liste și poate afișa o listă de operații de actualizare care convertește prima listă în cea de-a doua. ItemCallback
este o clasă statică abstractă interioară (interiorul DiffUtil
) utilizat pentru a calcula diferența dintre două elemente non-null dintr-o listă.
Mai exact, furnizăm PersonDiffCallback
pentru noi PagedListAdapter
constructor.
importand android.support.v7.util.DiffUtil import com.chikeandroid.pagingtutsplus.data.Person clasa PersonDiffCallback: DiffUtil.ItemCallback(oldItem: Person, newItem: Person?): boolean return oldItem.id == newItem.id suprascrie distracția areContentsTheSame (oldItem: Person ?, newItem: Person?):
Pentru că punem în aplicare DiffUtil.ItemCallback
, trebuie să implementăm două metode: areItemsTheSame ()
și areContentsTheSame ()
.
areItemsTheSame
este chemat să verifice dacă două obiecte reprezintă același element. De exemplu, dacă elementele dvs. au ID-uri unice, această metodă ar trebui să verifice egalitatea de identitate a acestora. Această metodă revine Adevărat
dacă cele două elemente reprezintă același obiect sau fals
dacă sunt diferite.areContentsTheSame
este chemat să verifice dacă două elemente au aceleași date. Această metodă revine Adevărat
dacă conținutul articolelor este același sau fals
dacă sunt diferite.Al nostru PersonViewHolder
clasa interioară este doar un tipic RecyclerView.ViewHolder
. Este responsabil pentru legarea datelor, după cum este necesar din modelul nostru, în widget-urile pentru un rând din lista noastră.
clasa PersonAdapter (contextul val: Context): PagedListAdapter(PersonDiewCallback ()) // ... clasa PersonViewHolder (vizualizare: Vizualizare): RecyclerView.ViewHolder (vizualizare) var tvName: TextView = nume de vizionare fun bind (person: Person) tvName.text = person.name () tvName.text = null
În a noastră onCreate ()
a noastră Activitate principala
, am făcut pur și simplu următoarele:
viewModel
utilizând clasa de utilitate ViewModelProviders
PersonAdapter
RecyclerView
PersonAdapter
la RecyclerView
LiveData
și trimiteți PagedList
obiecte de la PersonAdapter
invocând submitList ()
importați android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders importați android.os.Bundle import android.support.v7.app.AppCompatActivity import android.support.v7.widget.RecyclerView import com.chikeandroid.pagingtutsplus.adapter .PersonAdapter import com.chikeandroid.pagingtutsplus.viewmodels.PersonsViewModel class MainActivity: AppCompatActivity () privat lateinit var viewModel: PersonsViewModel suprascrie distracție onCreate (savedInstanceState: Bundle?) Super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) viewModel = ViewModelProviders.of (acest) .get (PersonsViewModel :: class.java) val adapter = PersonAdapter (acest) findViewById(Nume_aplicator_adaptator) adaptor subscribeUi adaptor privat subscribeUi (adaptor: PersonAdapter) viewModel.getPersonLiveData () observa (acest lucru, Observer names -> if (names! = Null) adapter.submitList (nume))
În cele din urmă, când rulați aplicația, iată rezultatul:
În timp ce derulați, camera este capabilă să prevină decalajele prin încărcarea a 50 de articole la un moment dat și a le pune la dispoziția noastră PersonAdapter
, care este o subclasă de PagingListAdapter
. Dar rețineți că nu toate sursele de date vor fi încărcate rapid. Viteza de încărcare depinde, de asemenea, de puterea de procesare a dispozitivului Android.
Dacă utilizați sau doriți să utilizați RxJava în proiectul dvs., biblioteca de paginare include un alt artefact util: RxPagedListBuilder
. Folosești acest artefact în loc de LivePagedListBuilder
pentru suportul RxJava.
Pur și simplu creați o instanță de RxPagedListBuilder
, furnizând aceleași argumente ca și dumneavoastră LivePagedListBuilder
- DataSource.Factory
și mărimea paginii. Apoi, sunați buildObservable ()
sau buildFlowable ()
pentru a reveni Observabil
sau curgător
pentru tine PagedList
respectiv.
Să furnizeze explicit Scheduler
pentru operația de încărcare a datelor, apelați metoda de setare setFetchScheduler ()
. Pentru a oferi, de asemenea, Scheduler
pentru livrarea rezultatului (de ex. AndroidSchedulers.mainThread ()
), pur și simplu sunați setNotifyScheduler ()
. În mod implicit, setNotifyScheduler ()
implicit la firul UI, în timp ce setFetchScheduler ()
implicit la piscina de file I / O.
În acest tutorial, ați învățat cum să utilizați cu ușurință componenta Paging din Componentele Android Architecture (care fac parte din Android Jetpack) împreună cu Room. Acest lucru ne ajută să încărcăm în mod eficient seturi mari de date din baza de date locală pentru a permite o experiență mai ușoară a utilizatorului în timp ce derulați printr-o listă în RecyclerView
.
Vă recomandăm să verificați documentația oficială pentru a afla mai multe despre biblioteca Paging din Android.