分頁緩存與下拉刷新的整合原理 - DoraPageDatabaseCacheRepository

何為分頁緩存?

顧名思義,分頁緩存就是邊分頁邊緩存,分頁通常使用下拉刷新控件實現,而緩存通常說的是指磁盤緩存,即保存到數據庫中,數據庫本身也是一個索引文件。

為什么緩存還要分頁?

在很大一部分場景下,緩存都是需要分頁的,不要問我為什么,問就是不懂規矩,哈哈。你家的接口一次性把整張表的數據全部都返回給你嗎?先不說用戶耗多少流量的問題,如果大家都一次性把表的數據都給你,那爬蟲何以生存?分分鐘就把你的數據全都弄走了,要知道,互聯網世界,數據就是資源,數據就是錢啊!

怎么使用下拉刷新分頁?

重復的問題不會再講,看我之前的文章Android低代碼開發 - 直接創建一個下拉刷新列表界面。下拉刷新和上拉加載都是用來分頁加載數據的。下拉刷新往往只加載第一頁的數據,而上拉加載則是加載下一頁的數據,如果有。

下拉刷新怎么和緩存結合起來?

這個問題問的好。本篇提到的緩存一律指數據庫緩存,而非內存緩存。當然我的dcache庫https://github.com/dora4/dcache-android 支持內存緩存,會簡單帶過。我以緩存系統通知列表為例。

package com.dorachat.dorachat.repositoryimport android.content.Context
import com.dorachat.dorachat.common.AppConfig.Companion.PRODUCT_NAME
import com.dorachat.dorachat.http.ApiResult
import com.dorachat.dorachat.http.service.HomeService
import com.dorachat.dorachat.model.SystemNotification
import dora.cache.data.adapter.ListResultAdapter
import dora.cache.data.fetcher.OnLoadStateListener
import dora.cache.factory.DatabaseCacheHolderFactory
import dora.cache.repository.DoraPageDatabaseCacheRepository
import dora.cache.repository.ListRepository
import dora.http.DoraListCallback
import dora.http.retrofit.RetrofitManager.getService
import retrofit2.Callback
import javax.inject.Inject@ListRepository
class SysNotificationRepository @Inject constructor(context: Context) :DoraPageDatabaseCacheRepository<SystemNotification>(context) {override fun onLoadFromNetwork(callback: DoraListCallback<SystemNotification>,listener: OnLoadStateListener?) {getService(HomeService::class.java).getSystemNotificationList(PRODUCT_NAME).enqueue(ListResultAdapter<SystemNotification, ApiResult<SystemNotification>>(callback)as Callback<ApiResult<MutableList<SystemNotification>>>)}override fun createCacheHolderFactory(): DatabaseCacheHolderFactory<SystemNotification> {return DatabaseCacheHolderFactory(SystemNotification::class.java)}
}

緩存倉庫,使用@ListRepository標記緩存的數據結構是列表類型的。使用咱們的DoraPageDatabaseCacheRepository,進行分頁數據的緩存。如果你不使用框架內置的ORM框架,則需要先整合你的ORM框架,具體看我專欄的其他文章。這個類就是為了告訴框架,你要緩存的數據結構是一個List類型的SystemNotification,而且會一頁一頁給到,請幫我緩存好了。我們知道list模式的BaseRepository使用流程是,先在activity設置一個數據監聽器,repository.getListLiveData().observe(this, observer),然后改變一下參數,repository.setXxx(),調用一下repository.fetchListData()。一旦調用抓取數據的函數,就會調用onLoadFromNetwork()方法,加載最新參數的數據,這邊的數據監聽器就會被回調,同時將數據緩存一份到數據庫中,以備無網絡的時候使用。附上DoraPageDatabaseCacheRepository的源碼你就明白了。

package dora.cache.repositoryimport android.content.Context
import android.util.Log
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import dora.cache.data.fetcher.OnLoadStateListener
import dora.db.builder.Condition
import dora.db.builder.QueryBuilder
import dora.db.table.OrmTableabstract class DoraPageDatabaseCacheRepository<T : OrmTable>(context: Context): DoraDatabaseCacheRepository<T>(context) {private var pageNo: Int = 0private var pageSize: Int = 10fun getPageNo(): Int {return pageNo}fun getPageSize(): Int {return pageSize}fun isLastPage(totalSize: Int) : Boolean {val lastPage = if (totalSize % pageSize == 0) totalSize / pageSize - 1 else totalSize / pageSizereturn lastPage == pageNo}fun observeData(owner: LifecycleOwner, adapter: AdapterDelegate<T>) {getListLiveData().observe(owner) {if (pageNo == 0) {adapter.setList(it)} else {adapter.addData(it)}}}interface AdapterDelegate<T> {fun setList(data: MutableList<T>)fun addData(data: MutableList<T>)}/*** 下拉刷新回調,可結合[setPageSize]使用。*/fun onRefresh(listener: OnLoadStateListener) {pageNo = 0fetchListData(listener = listener)}/*** 下拉刷新高階函數,可結合[setPageSize]使用。*/@JvmOverloadsfun onRefresh(block: ((Boolean) -> Unit)? = null) {pageNo = 0fetchListData(listener = object : OnLoadStateListener {override fun onLoad(state: Int) {block?.invoke(state == OnLoadStateListener.SUCCESS)}})}/*** 上拉加載回調,可結合[setPageSize]使用。*/fun onLoadMore(listener: OnLoadStateListener) {pageNo++fetchListData(listener = listener)}/*** 上拉加載高階函數,可結合[setPageSize]使用。*/@JvmOverloadsfun onLoadMore(block: ((Boolean) -> Unit)? = null) {pageNo++fetchListData(listener = object : OnLoadStateListener {override fun onLoad(state: Int) {block?.invoke(state == OnLoadStateListener.SUCCESS)}})}open fun setPageSize(pageSize: Int): DoraPageDatabaseCacheRepository<T> {this.pageSize = pageSizereturn this}open fun setCurrentPage(pageNo: Int, pageSize: Int): DoraPageDatabaseCacheRepository<T> {this.pageNo = pageNothis.pageSize = pageSizereturn this}override fun query(): Condition {val start = pageNo * pageSizereturn QueryBuilder.create().limit(start, pageSize).toCondition()}/*** 沒網的情況下直接加載緩存數據。*/override fun selectData(ds: DataSource): Boolean {var isLoaded = falseif (!isNetworkAvailable) {isLoaded = ds.loadFromCache(DataSource.CacheType.DATABASE)}return if (isNetworkAvailable) {try {ds.loadFromNetwork()true} catch (e: Exception) {Log.e(TAG, e.toString())isLoaded}} else isLoaded}
}

在這個分頁緩存倉庫類中,定義了分頁的一些參數,如第幾頁?每頁幾條數?onRefresh()和onLoadMore()完全就是為了配合下拉刷新控件而設計的。不會使用dcache庫的,是不是看源碼也能知道怎么調用?observeData()方法是不是就是我們剛才講到的數據監聽器,或者說觀察者。那么就來看一下調用層面的代碼吧。

package com.dorachat.dorachat.ui.activity.adminimport android.app.Activity
import android.content.Intent
import android.os.Build
import android.os.Bundle
import androidx.annotation.RequiresApi
import com.dorachat.dorachat.ChatAppimport com.dorachat.dorachat.R
import com.dorachat.dorachat.common.AppConfig.Companion.ACTION_UPDATE_SYS_NOTIFICATION
import com.dorachat.dorachat.common.AppConfig.Companion.PRODUCT_NAME
import com.dorachat.dorachat.common.AppConfig.Companion.REQUEST_CODE_ADD_SYS_NOTIFICATION
import com.dorachat.dorachat.common.AppConfig.Companion.REQUEST_CODE_UPDATE_SYS_NOTIFICATION
import com.dorachat.dorachat.common.IntentKeys.Companion.KEY_SYSTEM_NOTIFICATION
import com.dorachat.dorachat.databinding.ActivitySysNotificationBinding
import com.dorachat.dorachat.di.component.DaggerUserComponent
import com.dorachat.dorachat.http.service.HomeService
import com.dorachat.dorachat.model.SystemNotification
import com.dorachat.dorachat.model.request.ReqSysNotification
import com.dorachat.dorachat.repository.SysNotificationRepository
import com.dorachat.dorachat.ui.adapter.SysNotificationAdapter
import dora.cache.repository.DoraPageDatabaseCacheRepository
import dora.dagger.DaggerBaseActivity
import dora.http.DoraHttp
import dora.http.DoraHttp.net
import dora.http.retrofit.RetrofitManager
import dora.util.IntentUtils
import dora.util.ViewUtils
import dora.widget.DoraAlertDialog
import dora.widget.Tips
import dora.widget.pull.SwipeLayout
import javax.inject.Injectclass SysNotificationActivity : DaggerBaseActivity<ActivitySysNotificationBinding>() {@Inject lateinit var notificationRepository: SysNotificationRepositoryprivate val adapter = SysNotificationAdapter()override fun getLayoutId(): Int {return R.layout.activity_sys_notification}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (resultCode == Activity.RESULT_OK) {if (requestCode == REQUEST_CODE_ADD_SYS_NOTIFICATION ||requestCode == REQUEST_CODE_UPDATE_SYS_NOTIFICATION) {notificationRepository.onRefresh()}}}override fun onInjectDaggerComponent() {DaggerUserComponent.builder().appComponent(ChatApp.appComponent).build().inject(this)}@RequiresApi(Build.VERSION_CODES.O)override fun initData(savedInstanceState: Bundle?, binding: ActivitySysNotificationBinding) {binding.tvSysNotificationAdd.setOnClickListener {IntentUtils.startActivityForResult(SysNotificationEditorActivity::class.java, REQUEST_CODE_ADD_SYS_NOTIFICATION)}notificationRepository.observeData(this, object : DoraPageDatabaseCacheRepository.AdapterDelegate<SystemNotification> {override fun addData(data: MutableList<SystemNotification>) {adapter.addData(data)mBinding.emptyLayout.showContent()}override fun setList(data: MutableList<SystemNotification>) {adapter.setList(data)mBinding.emptyLayout.showContent()}})binding.slSysNotificationList.setOnSwipeListener(object : SwipeLayout.OnSwipeListener {override fun onRefresh(swipeLayout: SwipeLayout) {}override fun onLoadMore(swipeLayout: SwipeLayout) {if (!notificationRepository.isLastPage(notificationRepository.getTotalSize())) {notificationRepository.onLoadMore {swipeLayout.loadMoreFinish(if (it) SwipeLayout.SUCCEED else SwipeLayout.FAIL)}}}})ViewUtils.configRecyclerView(binding.recyclerView).adapter = adapternotificationRepository.onRefresh()adapter.addChildClickViewIds(R.id.ll_sys_notification_list, R.id.btn_delete)adapter.setOnItemChildClickListener { _, view, position ->when (view.id) {R.id.ll_sys_notification_list -> {val item = adapter.getItem(position)IntentUtils.startActivityForResultWithSerializable(this@SysNotificationActivity,SysNotificationEditorActivity::class.java,ACTION_UPDATE_SYS_NOTIFICATION,REQUEST_CODE_UPDATE_SYS_NOTIFICATION,KEY_SYSTEM_NOTIFICATION, item)}R.id.btn_delete -> {DoraAlertDialog(this).show(R.string.confirm_delete) {themeColorResId(R.color.colorPrimary)positiveListener {val item = adapter.getItem(position)net {val req = ReqSysNotification(productName = PRODUCT_NAME,id = item.id)val ok = DoraHttp.result {RetrofitManager.getService(HomeService::class.java).removeSystemNotification(req.toRequestBody())}?.dataif (ok == true) {adapter.removeAt(position)Tips.showSuccess(R.string.deleted_successfully)}}}}}}}}
}

這里用到了Dagger的依賴注入,不在本篇的討論范圍。DoraPageDatabaseCacheRepository.AdapterDelegate告訴適配器,你就在我的回調里面更新數據就好了。

在哪里去找緩存庫相關源碼?

https://github.com/dora4/dcache-android 緩存庫

https://github.com/dora4/dview-swipe-layout 下拉刷新控件

https://github.com/dora4/dview-empty-layout 空態頁面

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38458.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38458.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38458.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SSH 無密登錄配置流程

一、免密登錄原理 非對稱加密&#xff1a; 由于對稱加密的存在弊端&#xff0c;就產生了非對稱加密&#xff0c;非對稱加密中有兩個密鑰&#xff1a;公鑰和私鑰。公鑰由私鑰產生&#xff0c;但卻無法推算出私鑰&#xff1b;公鑰加密后的密文&#xff0c;只能通過對應的私鑰來解…

光速入門 Tailwind CSS

文章目錄 入門安裝IDE 設置使用預編譯器生產環境優化 基礎概念分層指令tailwindlayerapplyconfig 函數theme()screen() 基礎案例怎么設置屬性任意值&#xff1f;hover 父元素時&#xff0c;怎么選中子元素添加樣式&#xff1f;添加 animation 動畫 配置主題 Tailwind CSS 中文網…

.so: file not recognized: file format not recognized

項目場景&#xff1a; 自Linux 4.8起&#xff0c;傳統的GPIO sysfs接口被棄用。libgpiod操作gpio的方式感覺更加方便。 但是單板上好像沒裝這個工具&#xff0c;又到了熟悉的交叉編譯環節&#xff08;痛苦&#xff09;。 問題描述 按照流程裝完libgpiod&#xff0c;自信地去交…

安卓Gradle學習與應用:從入門到實踐

引言 在Android開發的世界里&#xff0c;Gradle不僅僅是一個構建工具&#xff0c;它更是一種強大的自動化系統&#xff0c;能夠幫助開發者高效地管理項目依賴、編譯、測試、打包以及部署。本篇博客旨在深入探討Gradle在Android開發中的應用&#xff0c;從基礎概念到實戰技巧&a…

334. 遞增的三元子序列

334. 遞增的三元子序列 題目鏈接&#xff1a;334. 遞增的三元子序列 代碼如下&#xff1a; class Solution { public://貪心bool increasingTriplet(vector<int>& nums) {if(nums.size()<3) {return false;}int firstnums[0],secondINT_MAX;for(int i1;i<…

Go源碼--context包

簡介 Context 是go語言比較重要的且也是比較復雜的一個結構體&#xff0c;Context主要有兩種功能: 取消信號&#xff1a;包括直接取消&#xff08;涉及的結構體&#xff1a;cancelCtx ; 涉及函數&#xff1a;WithCancel&#xff09;和攜帶截止日期的取消&#xff08;涉及結構…

密室逃脫——收集版

一、原版修改 1、導入資源 Unity Learn | 3D Beginner: Complete Project | URP 2、設置Scene 刪除SampleScene&#xff0c;打開UnityTechnologies-3DBeginnerComplete下的MainScene 3、降低音量 (1) 打開Hierarchy面板上的Audio降低音量 (2) 打開Prefabs文件夾&#xf…

Git安裝與使用及整合IDEA使用的詳細教程

1. 版本控制軟件介紹 版本控制軟件提供完備的版本管理功能&#xff0c;用于存儲、追蹤目錄&#xff08;文件夾&#xff09;和文件的修改歷史&#xff0c;是軟件開發者的必備工具&#xff0c;是軟件公司的基礎設施。版本控制軟件的最高目標&#xff0c;是支持軟件公司的配置管理…

第三天:LINK3D核心原理講解【第2部分】

三、 變量 // 點云容器 pcl::PointCloud<pcl::PointXYZI> laserCloud; // 一幀原始點云 pcl::PointCloud<pcl::PointXYZI> cornerPointsLessSharp; // 次極大邊線點 pcl::PointCloud<pcl::PointXYZI> surfPointsLessFlat; // 次極小平面點 pcl::PointCloud&…

ubuntu中后臺啟動一個jar

1.使用 nohup 和 & 啟動應用程序&#xff1a; nohup java -jar 你的jar包.jar > output.log 2>&1 &解釋&#xff1a; nohup&#xff1a;忽略掛起信號&#xff08;SIGHUP&#xff09;&#xff0c;使進程在退出終端后繼續運行。java -jar lxyoj-code-sandbox-…

管理統計學

第1章 統計學是收集、處理、分析、解釋數據并從數據中得出結論的科學。 統計學是處理數據的方法論。 參數 表示總體特征的概括性數字度量&#xff0c;是研究者想要了解的總體的某種特征值。 統計量 是用來描述樣本特征的概括性數字度量。 常用統計量包括&#xff1a; &#xff…

達夢數據庫系列—14. 表空間的備份和還原

目錄 1、表空間備份 2、表空間還原 3、表空間恢復 4、增量還原恢復 1、表空間備份 表空間只能在聯機狀態下進行備份。 BACKUP TABLESPACE TBS BACKUPSET /dm/backup/dm_bak/ts_bak_01; 完全備份 BACKUP TABLESPACE TBS FULL BACKUPSET /dm/backup/dm_bak/ts_full_bak_01…

ESP8266[ 關于-巴發云MQTT/TCP:arduino 設置回調函數 ] 日志2024/6/29

ESP8266 [ 關于-巴發云MQTT/TCP:arduino 設置回調函數 ] 日志2024/6/29 arduino庫:#include <PubSubClient.h> 回調函數 是其庫設置好的 可以改名字 這里只寫上關鍵代碼 設置客戶端為 A 關鍵代碼: A.setCallback(回調名) //MQTT 回調處理mqttmsgg(自定義…

zdppy_api+vue3實現前后端分離的登錄功能

實現思路 1、準備zdppy的開發環境 2、使用amauth提供的低代碼接口&#xff0c;直接生成login登錄接口 3、使用之前開發的登錄模板渲染登錄界面 4、給登錄按鈕綁定點擊事件 5、給用戶名和密碼的輸入框雙向綁定數據 6、使用axios在登錄按鈕點擊的時候&#xff0c;攜帶用戶數據發…

PySide(PyQt)與OpenCV圖像格式的相互轉換

PySide和OpenCV在圖像格式上的區別&#xff1a; 主要表現在圖像數據的存儲方式和使用場景上。以下是一些關鍵區別&#xff1a; 1. 數據結構 PySide: QImage 和 QPixmap 是 PySide 中常用的圖像表示形式。 QImage&#xff1a;用于直接訪問圖像的像素數據&#xff0c;適合需要…

C++ | Leetcode C++題解之第207題課程表

題目&#xff1a; 題解&#xff1a; class Solution { private:vector<vector<int>> edges;vector<int> indeg;public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {edges.resize(numCourses);indeg.resize(numCo…

MyBatis(15)MyBatis 的延遲加載是如何實現

MyBatis 的延遲加載&#xff08;懶加載&#xff09;特性允許在需要使用關聯對象數據時才進行加載&#xff0c;而不是在執行主查詢時就加載所有相關數據。這種機制可以提高應用程序的性能&#xff0c;特別是當關聯數據龐大或關聯層次較深時。我們將通過以下幾個方面來深入了解My…

昇思25天學習打卡營第13天|MindNLP ChatGLM-6B StreamChat

學AI還能贏獎品&#xff1f;每天30分鐘&#xff0c;25天打通AI任督二脈 (qq.com) MindNLP ChatGLM-6B StreamChat 本案例基于MindNLP和ChatGLM-6B實現一個聊天應用。 1 環境配置 %%capture captured_output # 實驗環境已經預裝了mindspore2.2.14&#xff0c;如需更換mindspo…

[知識點篇]《計算機組成原理》之數據信息的表示

1、數據表示的作用 &#xff08;1&#xff09;定義&#xff1a;將數據按照某種方式組織&#xff0c;以便機器硬件能直接識別和使用。現代計算機采用二進制進行數據表示。 &#xff08;2&#xff09;數據表示考慮因素&#xff1a; 數據的類型&#xff1a; 數值/非數值、小數、…

讀AI新生:破解人機共存密碼筆記17不確定性和概率

1. 前向搜索 1.1. 通過前向搜索&#xff0c;通過考慮各種可能的動作序列的結果&#xff0c;來選擇動作&#xff0c;是智能系統的基本能力 1.2. 如果一家卡車運輸公司想要優化其100輛卡車在美國的運輸&#xff0c;那么該公司可能需要考慮的狀態數量將是10^700個 1.3. 幾乎所有…