RemoteMediator dan Pencachean
Gabungkan pemenggalan rangkaian dan pangkalan data.
RemoteMediator dan Pencachean ialah pelajaran Android Academy percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Android Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Android Academy merangkumi sejumlah 4 pelajaran.
Penomboran Luar Talian Terlebih Dahulu
PagingSource rangkaian biasa boleh berfungsi, tetapi apabila sambungan terputus, senarai menjadi kosong. Untuk aplikasi yang teguh, anda mahukan pangkalan data sebagai sumber kebenaran tunggal dan rangkaian mengisinya di latar belakang.
Itulah yang didayakan oleh RemoteMediator: halaman diambil daripada pangkalan data setempat, dan data tambahan diambil daripada rangkaian apabila pangkalan data kehabisan data.
Seni Bina
Dengan RemoteMediator, data mengalir dalam satu arah:
- UI mendapatkan halaman daripada
PagingSourceRoom - Apabila Room menghampiri penghujungnya,
RemoteMediatormengambil halaman rangkaian seterusnya - Hasil rangkaian ditulis ke dalam Room
- Room memancarkan baris baharu, lalu UI dikemas kini
Pengguna sentiasa melihat data cache dengan serta-merta, walaupun di luar talian.
// Network ---> RemoteMediator ---> Room (source of truth) ---> UI
// UI never reads the network directlyPagingSource Room Secara Automatik
Room boleh menjana PagingSource secara automatik. Anda hanya perlu mengisytiharkan pertanyaan yang mengembalikan PagingSource<Int, Entity>, dan Room akan melaksanakannya.
Inilah sumber yang sebenarnya digunakan oleh UI untuk mendapatkan halaman.
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Query
@Dao
interface ArticleDao {
@Query("SELECT * FROM articles ORDER BY position ASC")
fun pagingSource(): PagingSource<Int, ArticleEntity>
}Mewarisi RemoteMediator
RemoteMediator<Key, Value> mempunyai satu kaedah yang diperlukan, iaitu load(), serta initialize() yang pilihan.
load() menerima LoadType (REFRESH, PREPEND atau APPEND) dan PagingState semasa, kemudian mengembalikan MediatorResult.
import androidx.paging.ExperimentalPagingApi
import androidx.paging.RemoteMediator
@OptIn(ExperimentalPagingApi::class)
class ArticleRemoteMediator(
private val api: ArticleApi,
private val db: AppDatabase
) : RemoteMediator<Int, ArticleEntity>() {
// override suspend fun load(loadType, state): MediatorResult
}Mengendalikan LoadType
Dalam load(), anda menentukan halaman yang hendak diambil berdasarkan LoadType:
- REFRESH - memuatkan halaman pertama (atau halaman di sekitar penambat)
- PREPEND - biasanya tiada apa-apa yang perlu dilakukan; kembalikan
endOfPaginationReached = true - APPEND - memuatkan halaman selepas halaman terakhir yang kita ada
val page: Int = when (loadType) {
LoadType.REFRESH -> 1
LoadType.PREPEND ->
return MediatorResult.Success(endOfPaginationReached = true)
LoadType.APPEND -> {
val lastKey = db.remoteKeyDao().last()?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = true)
lastKey
}
}Jadual Kunci Jauh
Tidak seperti PagingSource, RemoteMediator tidak boleh mengembalikan kunci seterusnya/sebelumnya secara terus - kunci tersebut mesti disimpan. Simpannya dalam jadual kunci jauh yang kecil bersama-sama data anda.
Ini membolehkan anda menyambung semula APPEND/PREPEND selepas aplikasi dimulakan semula.
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "remote_keys")
data class RemoteKey(
@PrimaryKey val articleId: Int,
val prevKey: Int?,
val nextKey: Int?
)Menulis Hasil Rangkaian ke Room
Selepas mengambil halaman, tulis item dan kuncinya ke dalam Room dalam satu transaksi. Semasa REFRESH, kosongkan jadual lama terlebih dahulu supaya cache kekal konsisten.
db.withTransaction {
if (loadType == LoadType.REFRESH) {
db.remoteKeyDao().clearAll()
db.articleDao().clearAll()
}
val nextKey = if (response.items.isEmpty()) null else page + 1
db.remoteKeyDao().insertAll(
response.items.map { RemoteKey(it.id, prevKey = page - 1, nextKey = nextKey) }
)
db.articleDao().insertAll(response.items.map { it.toEntity() })
}Mengembalikan MediatorResult
Lengkapkan load() dengan mengembalikan MediatorResult:
Success(endOfPaginationReached = true)apabila tiada lagi halamanSuccess(endOfPaginationReached = false)apabila mungkin masih ada halamanError(e)apabila berlaku kegagalan - dipaparkan sebagaiLoadState.Error
return try {
val response = api.getArticles(page = page, size = state.config.pageSize)
db.withTransaction { /* write items + keys */ }
MediatorResult.Success(
endOfPaginationReached = response.items.isEmpty()
)
} catch (e: IOException) {
MediatorResult.Error(e)
} catch (e: HttpException) {
MediatorResult.Error(e)
}Menyambungkan Pager dengan remoteMediator
Bina Pager dengan kedua-dua remoteMediator dan pagingSourceFactory Room. Mediator mengisi Room; UI mendapatkan halaman daripada Room.
Oleh sebab ini menggunakan API percubaan, aktifkan penyertaan dengan @OptIn(ExperimentalPagingApi::class).
@OptIn(ExperimentalPagingApi::class)
fun articles(): Flow<PagingData<ArticleEntity>> = Pager(
config = PagingConfig(pageSize = 20),
remoteMediator = ArticleRemoteMediator(api, db),
pagingSourceFactory = { db.articleDao().pagingSource() }
).flowMencari Kunci untuk APPEND
Untuk pemuatan APPEND, anda memerlukan nextKey bagi item terakhir yang dimuatkan. Gunakan penambat PagingState untuk mencari kunci jauh yang betul daripada jadual kunci anda.
Fungsi pembantu menjadikan load() lebih mudah dibaca merentasi REFRESH, APPEND dan PREPEND.
private suspend fun lastRemoteKey(
state: PagingState<Int, ArticleEntity>
): RemoteKey? {
return state.pages.lastOrNull { it.data.isNotEmpty() }
?.data?.lastOrNull()
?.let { db.remoteKeyDao().keyFor(it.id) }
}
// In load(): for APPEND
val nextKey = lastRemoteKey(state)?.nextKey
?: return MediatorResult.Success(endOfPaginationReached = true)Pencachean dan Kesegaran
Oleh sebab data berada dalam Room, aplikasi dimuatkan serta-merta dan berfungsi di luar talian. Untuk mengelakkan kandungan lapuk, gantikan initialize() bagi menentukan sama ada perlu melakukan muat semula semasa pelancaran berdasarkan usia cache.
override suspend fun initialize(): InitializeAction {
val lastUpdate = db.remoteKeyDao().lastUpdatedMillis() ?: 0L
val cacheTimeout = TimeUnit.HOURS.toMillis(1)
return if (System.currentTimeMillis() - lastUpdate >= cacheTimeout) {
InitializeAction.LAUNCH_INITIAL_REFRESH
} else {
InitializeAction.SKIP_INITIAL_REFRESH
}
}Semakan Pantas
Dalam persediaan RemoteMediator, apakah sumber kebenaran tunggal yang digunakan oleh UI untuk mendapatkan halaman?
Imbas Kembali: RemoteMediator dan Pencachean
Anda telah membina saluran penomboran luar talian terlebih dahulu:
- UI mendapatkan halaman daripada
PagingSourceRoom - sumber kebenaran tunggal RemoteMediator.load()mengendalikanREFRESH/PREPEND/APPENDdan menulis hasil ke Room dalam satu transaksi- Jadual kunci jauh menyimpan kunci seterusnya/sebelumnya selepas aplikasi dimulakan semula
Pagermenerima kedua-duaremoteMediatordanpagingSourceFactoryinitialize()mengawal kesegaran cache
Pelajari Kotlin dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 36
- Pelajaran
- 152
Soalan Lazim
Adakah pelajaran “RemoteMediator dan Pencachean” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Android Academy, termasuk “RemoteMediator dan Pencachean”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Android Academy merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “RemoteMediator dan Pencachean”?
Gabungkan pemenggalan rangkaian dan pangkalan data. Anda berlatih Android Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan Android Academy?
Tiada pengalaman terdahulu diperlukan. Pembelajaran Android Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.
Berapa lamakah pelajaran “RemoteMediator dan Pencachean” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran Android Academy ini?
Ya. Setiap pelajaran Android Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Sebab Pemenggalan
- PagingSource dan Pager
- Pemenggalan dalam Senarai Compose
- RemoteMediator dan Pencachean