中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

慶陽(yáng)網(wǎng)站建設(shè)百度推廣在哪里

慶陽(yáng)網(wǎng)站建設(shè),百度推廣在哪里,可以看的網(wǎng)站的瀏覽器有哪些,大連網(wǎng)站建設(shè)免費(fèi)在Android上,經(jīng)常會(huì)需要持久化本地?cái)?shù)據(jù),比如我們需要緩存用戶的配置信息、用戶的數(shù)據(jù)、緩存數(shù)據(jù)、離線緩存數(shù)據(jù)等等。我們通常使用的工具為SharePreference、MMKV、DataStore、Room、文件等等。通過(guò)使用現(xiàn)有的存儲(chǔ)框架,結(jié)合協(xié)程,我…

在Android上,經(jīng)常會(huì)需要持久化本地?cái)?shù)據(jù),比如我們需要緩存用戶的配置信息、用戶的數(shù)據(jù)、緩存數(shù)據(jù)、離線緩存數(shù)據(jù)等等。我們通常使用的工具為SharePreference、MMKV、DataStore、Room、文件等等。通過(guò)使用現(xiàn)有的存儲(chǔ)框架,結(jié)合協(xié)程,我們可以方便地實(shí)現(xiàn)一個(gè)輕量級(jí)的響應(yīng)式存儲(chǔ)框架。

在使用的場(chǎng)景上,我們使用Key-Value的場(chǎng)景很多,而且我們往往不僅僅是存儲(chǔ)數(shù)據(jù)、獲取數(shù)據(jù),經(jīng)常還有需要序列化存儲(chǔ)、加密存儲(chǔ)、訂閱數(shù)據(jù)的變化的功能。

訂閱數(shù)據(jù)的變化,常見(jiàn)的就是使用發(fā)布/訂閱模式來(lái)實(shí)現(xiàn)。

但是使用類如EventBus和RxBus并不是一個(gè)好的實(shí)踐,EventBus沒(méi)有做適當(dāng)?shù)姆庋b被濫用的話,會(huì)導(dǎo)致邏輯混亂,難以跟蹤,并且調(diào)試起來(lái)也相當(dāng)困難。

谷歌的DataStore就是一個(gè)很好的實(shí)現(xiàn)。除了DataStore,我們其實(shí)也可以使用基于現(xiàn)有的SharePreference、MMKV通過(guò)協(xié)程等來(lái)實(shí)現(xiàn)我們的響應(yīng)式存儲(chǔ)框架。

下面我們就來(lái)設(shè)計(jì)這個(gè)存儲(chǔ)框架。

首先我們基于我們的功能來(lái)定義我們的接口

我們的功能如下

  1. 1.支持存儲(chǔ)和讀取
  2. 2.支持加密和解密
  3. 3.支持序列化和反序列化
  4. 4.支持多“倉(cāng)庫(kù)"

由此我們定義了3組接口

  1. 1.Storage 存儲(chǔ)器
  2. 2.Serializer 序列化器
  3. 3.CryptoHandler 加密和解密處理器

在清潔架構(gòu)的分層中,存儲(chǔ)(Storage)是屬于一種"接口適配器",因?yàn)樗鼮閼?yīng)用的內(nèi)部業(yè)務(wù)邏輯(即領(lǐng)域?qū)?#xff09;提供了與外部世界(即數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)、文件系統(tǒng)等)的接口。一般在Respository中和這些接口適配器進(jìn)行通訊來(lái)獲取和存儲(chǔ)數(shù)據(jù),所以在設(shè)計(jì)Storage的時(shí)候,我們應(yīng)該遵循下面的概念。

Storage接口定義了一個(gè)抽象的存儲(chǔ)協(xié)議,不關(guān)注具體的實(shí)現(xiàn)方式,例如使用SharedPreferences,MMKV,或者DataStore,這正是適配器層的職責(zé)。通過(guò)適配器層,我們可以使得業(yè)務(wù)邏輯從具體的技術(shù)細(xì)節(jié)中解耦,使其更關(guān)注于應(yīng)用的業(yè)務(wù)規(guī)則,而不是底層的存儲(chǔ)細(xì)節(jié)。

同時(shí),我們的設(shè)計(jì)要允許我們根據(jù)需要,靈活地更換或者修改存儲(chǔ)的具體實(shí)現(xiàn),而無(wú)需改動(dòng)業(yè)務(wù)邏輯或者其他部分的代碼。

而這正是清潔架構(gòu)的一個(gè)重要原則:獨(dú)立性和隔離變化,即依賴抽象而不是具體實(shí)現(xiàn)。

基于此設(shè)計(jì)如下的存儲(chǔ)器接口

interface Storage {fun put( key:String, obj:Any?)operator fun <T> get( key: String, classOfT:Class<T>):T?operator fun <T> get( key: String, typeOfT: Type):T?fun contain( key: String):Booleanfun onKeyChanged( key:String): Flow<String>fun remove( key: String)fun removeAllPrefix( prefixKey:String )fun removeExcludePrefix( vararg prefixKey: String )fun clear()
}
inline operator fun <reified T> Storage.get(key: String): T? {return get(key, T::class.java)
}

Storage接口設(shè)計(jì)將基本的存儲(chǔ)操作抽象化,并通過(guò)onKeyChanged提供了數(shù)據(jù)變化的通知,這是一個(gè)非常有用的功能,使得可以對(duì)存儲(chǔ)數(shù)據(jù)的改變進(jìn)行反應(yīng)。

此外,removeAllPrefix和removeExcludePrefix方法也為更精細(xì)的數(shù)據(jù)控制提供了可能性,這在處理具有特定前綴鍵值對(duì)的場(chǎng)景中非常有用。

Storage接口設(shè)計(jì)的目的是為了隱藏實(shí)現(xiàn)細(xì)節(jié)和提高代碼的可讀性、可維護(hù)性和可擴(kuò)展性。

下面我們基于此繼續(xù)擴(kuò)展我們的Storage功能

首先,我們的數(shù)據(jù)我們希望是序列化存儲(chǔ)的,并且可以支持加密。

因此我們繼續(xù)定義接口:


interface Serializer {fun serialize(obj: Any): Stringfun <T> deserialize(obj: String, classOfT: Class<T>): Tfun <T> deserialize(obj: String, typeOfT: Type): T
}
inline fun <reified T> Serializer.deserialize(obj: String): T = deserialize(obj, T::class.java)

然后是加密和解密接口:

interface CryptoHandler {fun encrypt(obj: String): Stringfun decrypt(obj: String): String
}

接下來(lái)我們就可以使用這兩個(gè)接口來(lái)執(zhí)行序列化、反序列化,加密和解密的操作。

首先MMKV是支持加密的,但是MMKV使用的是AES CFB-128加密算法來(lái)做的。但是它并不是那么足夠安全,它沒(méi)有提供硬件級(jí)別的安全加密方法。所以可以考慮自己使用Android KeyStore 來(lái)實(shí)現(xiàn)硬件級(jí)別的加密。

使用Android Keystore來(lái)實(shí)現(xiàn),一般大致思路就是拿使用Android的keystore 創(chuàng)建一組加密對(duì)密鑰,然后使用AES算法來(lái)加密和解密。

序列化我們可以使用ProtoBuf或者是json來(lái)實(shí)現(xiàn)

下面簡(jiǎn)單使用gson來(lái)實(shí)現(xiàn)我們的序列化存儲(chǔ)如下:

@Singleton
open class JsonSerializer(private val gson: Gson) : Serializer {override fun serialize(obj: Any): String {return gson.toJson(obj)}override fun <T> deserialize(obj: String, classOfT: Class<T>): T {return gson.fromJson(obj, classOfT)}override fun <T> deserialize(obj: String, typeOfT: Type): T {return gson.fromJson(obj, typeOfT)}
}

定義好了接口,實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單了,只需要在修改key-value的時(shí)候,發(fā)送一個(gè)key被修改的消息到一個(gè)flow,對(duì)flow的訂閱者就可以訂閱數(shù)據(jù)的改變了。

接下來(lái)我們基于MMKV和SharePreference來(lái)實(shí)現(xiàn)這個(gè)存儲(chǔ)接口

首先我們來(lái)使用SharePreference和MMKV來(lái)實(shí)現(xiàn)這個(gè)存儲(chǔ)功能
?

class SharePreferenceStorage (private val context: Context,private val storageType: StorageType,private val serializer: Serializer,private val eventLogger: StorageLogger?,private val cryptoHandler: CryptoHandler?):Storage{private val sharedPreferences: SharedPreferences =context.getSharedPreferences(storageType.alias, Context.MODE_PRIVATE)private val keyChangedFlow = MutableSharedFlow<String>(replay = 100)override fun put(key: String, obj: Any?) {obj?.let {data->sharedPreferences.edit().let {editor->editor.putString( key , serializer.serialize( data ).let {cryptoHandler?.encrypt( it )?:it} )editor.apply()keyChangedFlow.tryEmit( key )eventLogger?.trackEvent(StorageSaveEvent( getStorageName(),key, cryptoHandler != null))}}?: run {remove(key)}}override fun <T> get(key: String, classOfT: Class<T>): T? {sharedPreferences.getString( key ,null  )?.let {cryptoHandler?.decrypt( it )?:it}?.let {eventLogger?.trackEvent(StorageLoadEvent( getStorageName(),key, true))serializer.deserialize( it ,classOfT)}?.let {return it}?:run{return null}}override fun <T> get(key: String, typeOfT: Type): T? {val serializeString =   sharedPreferences.getString( key ,null  )?.let {cryptoHandler?.decrypt( it )?:it}return serializeString?.let {serializer.deserialize( it ,typeOfT)}}override fun onKeyChanged(key: String): Flow<String> {return keyChangedFlow.asSharedFlow()}override fun contains(key: String): Boolean {return sharedPreferences.contains( key )}override fun remove(key: String) {if( contains( key ) ){sharedPreferences.edit().let {editor->editor.remove( key )editor.apply()keyChangedFlow.tryEmit( key )eventLogger?.trackEvent(StorageRemoveEvent( getStorageName(),key))}}}override fun removeAllPrefix(prefixKey: String) {sharedPreferences.all?.let {allData->allData.keys.filter { it.startsWith( prefixKey ) }.forEach {remove( it )}}}override fun removeExcludePrefix(vararg prefixKey: String) {sharedPreferences.all?.let {allData->val prefixSet = prefixKey.toSet()val allKeys = allData.keysallKeys.forEach { key ->if (prefixSet.none { key.startsWith(it) }) {remove(key)}}}}override fun clear() {sharedPreferences.edit().let {editor->sharedPreferences.all.keys.forEach {remove( it )}keyChangedFlow.tryEmit( CLEAR_CACHE )eventLogger?.trackEvent(StorageClearEvent( getStorageName()))}}private fun getStorageName():String{return "SharePreference-${storageType.alias}"}}

下面是基于MMKV的實(shí)現(xiàn):

class MMKVStorage constructor(private val storageType: StorageType,private val serializer: Serializer,private val eventLogger: StorageLogger?,private val cryptoHandler: CryptoHandler?): Storage {private val mmkv: MMKV = MMKV.mmkvWithID( storageType.alias, MMKV.MULTI_PROCESS_MODE)private val keyChangedFlow = MutableSharedFlow<String>(replay = 100)private val subscribeKeyList:MutableList<String> = mutableListOf()override fun put(key: String, obj: Any?) {obj?.let {val serializerObj = serializer.serialize( obj ).let {cryptoHandler?.encrypt( it )?:it}mmkv.encode( key,serializerObj)keyChangedFlow.tryEmit(key)eventLogger?.trackEvent(StorageSaveEvent( getStorageName(),key, cryptoHandler != null))} ?: run{remove(key)}}override fun <T> get(key: String, classOfT: Class<T>): T? {return mmkv.decodeString( key )?.let{ jsonString->eventLogger?.trackEvent(StorageLoadEvent( getStorageName(),key, true))serializer.deserialize(jsonString.let {cryptoHandler?.decrypt(it)?:it},classOfT)}}override fun <T> get(key: String, typeOfT: Type): T? {return mmkv.decodeString( key)?.let { jsonString->eventLogger?.trackEvent(StorageLoadEvent( getStorageName(),key, true))serializer.deserialize( jsonString.let {cryptoHandler?.decrypt(it)?:it}, typeOfT)}}override fun onKeyChanged(key: String): Flow<String> {subscribeKeyList.add(key)return keyChangedFlow.asSharedFlow().filter { it == key }}override fun contains(key: String): Boolean {return mmkv.containsKey( key )}override fun remove(key: String) {mmkv.remove(key).apply()eventLogger?.trackEvent(StorageRemoveEvent( getStorageName(),key))keyChangedFlow.tryEmit( key )}override fun removeAllPrefix( prefixKey:String ){val allKeys = mmkv.allKeys()?.clone()?: emptyArray()allKeys.forEach { if( it.contains(prefixKey)) remove(it) }}override fun removeExcludePrefix(vararg prefixKey: String) {val allKeys = mmkv.allKeys()?.clone() ?: emptyArray()val prefixSet = prefixKey.toSet()allKeys.forEach { key ->if (prefixSet.none { key.startsWith(it) }) {remove(key)}}}override fun clear() {mmkv.allKeys()?.forEach {remove(it)}keyChangedFlow.tryEmit( Storage.CLEAR_CACHE )mmkv.clearAll()eventLogger?.trackEvent(StorageClearEvent( getStorageName()))}private fun getStorageName():String {return "mmkv-${storageType.alias}"}}

通過(guò)上面的代碼,我們就可以實(shí)現(xiàn)訂閱數(shù)據(jù)的改變。

http://www.risenshineclean.com/news/44918.html

相關(guān)文章:

  • 廣州市網(wǎng)站建設(shè)公司在哪里企業(yè)郵箱域名
  • 四川政府網(wǎng)站建設(shè)管理辦法什么是網(wǎng)絡(luò)營(yíng)銷的核心
  • 團(tuán)購(gòu)網(wǎng)站平臺(tái)建設(shè)什么公司適合做seo優(yōu)化
  • 海口做網(wǎng)站的公司如何做好營(yíng)銷
  • 新網(wǎng)站前期如何做seo怎么在百度免費(fèi)推廣
  • 諸暨網(wǎng)站制作哪些公司制作西安網(wǎng)站制作推廣
  • 荊州網(wǎng)站建設(shè)seo門戶 site
  • 泰和網(wǎng)站制作網(wǎng)站空間
  • 什么網(wǎng)站建設(shè)最簡(jiǎn)單騰訊3大外包公司
  • wordpress購(gòu)買服務(wù)器百度seo搜索營(yíng)銷新視角
  • 專門做app的網(wǎng)站內(nèi)容營(yíng)銷策略
  • 銅仁市網(wǎng)站建設(shè)情況上海百度推廣電話
  • 合肥網(wǎng)站推廣 公司哪家好最好看免費(fèi)觀看高清大全
  • 鄭州建網(wǎng)站多少河南整站百度快照優(yōu)化
  • 做網(wǎng)站除了廣告還有什么收入的種子搜索神器網(wǎng)頁(yè)版
  • 百度做網(wǎng)站一鍵優(yōu)化清理加速
  • 建網(wǎng)站個(gè)人主機(jī)做服務(wù)器天津seo選天津旗艦科技a
  • 重慶社區(qū)官網(wǎng)太原seo關(guān)鍵詞排名
  • 企業(yè)網(wǎng)站建設(shè)的一般要素包括6百度下載官網(wǎng)
  • 產(chǎn)品宣傳片制作公司seo網(wǎng)站關(guān)鍵詞排名優(yōu)化公司
  • 中國(guó)在菲律賓做網(wǎng)站百度知道首頁(yè)
  • 設(shè)計(jì)類專業(yè)網(wǎng)站西安核心關(guān)鍵詞排名
  • 哪個(gè)網(wǎng)站做非洲的生意站長(zhǎng)素材
  • 做網(wǎng)站經(jīng)常加班還是appdz論壇seo
  • 購(gòu)買域名后如何使用搜索網(wǎng)站排名優(yōu)化
  • 給網(wǎng)站首頁(yè)圖片做外網(wǎng)超鏈接_為什么會(huì)彈出一個(gè)服務(wù)器登錄窗口網(wǎng)頁(yè)制作成品
  • 那些網(wǎng)站可以接私活做比較好的免費(fèi)網(wǎng)站
  • 北京網(wǎng)站優(yōu)化公司如何輿情分析報(bào)告模板
  • 自己在線制作logo免費(fèi)頭像大連網(wǎng)絡(luò)營(yíng)銷seo
  • 怎么建網(wǎng)站做推廣太原網(wǎng)站關(guān)鍵詞排名