MVVM框架的搭建(一)——背景 MVVM框架的搭建(二)——項目搭建 MVVM框架的搭建(三)——網絡請求 MVVM的數據持久化(一)——ROOM的集成
ROOM的使用以及實踐
上一篇文章,我們已經介紹了MVVM持久化的意義以及工具ROOM,下面我們介紹一下如何在我們項目當中使用,已達到對數據持久化。
修改Model層
這裏我們需要修改一下Model層,添加Repository作爲ViewModel層的數據源,在Repository裏我們進行數據的處理判斷
package yang.cehome.com.mvvmdemo.model.repository import yang.cehome.com.mvvmdemo.model.local.dao.PostDao import yang.cehome.com.mvvmdemo.model.remote.PostService /** * @author yangzc * @data 2018/11/6 11:55 * @desc PostRepo * */ class PostRepo constructor(private val remote: PostService, private val local: PostDao){ //首先查看本地數據庫是否有數據 fun getPostInfo() = local.getPostInfo() .onErrorResumeNext { //本地數據庫不存在,會拋出會拋出EmptyResultSetException //轉而進行獲取網絡數據,成功後保存在數據庫 remote.getPostInfo().doOnSuccess { local.inserttPost(it) } } }
我們可以看到現在的項目結構爲:
項目結構
修改我們的ViewModel層的數據源
以前我們都是以PostService作爲數據源,現在我們要以PostRepo作爲數據源,這裏我們只需要修改
package yang.cehome.com.mvvmdemo.viewmodel import android.databinding.ObservableField import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers import yang.cehome.com.mvvmdemo.model.local.dao.PostEntity import yang.cehome.com.mvvmdemo.model.repository.PostRepo /** * @author yangzc * @data 2018/11/7 10:26 * @desc PostViewModel * */ class PostViewModel(private val repo: PostRepo) { /******data******/ val postinfo = ObservableField<String>() /******binding******/ fun loadpost() { repo.getPostInfo() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ t: PostEntity? -> postinfo.set(t?.let { it.toString() }) }, { t: Throwable? -> postinfo.set(t?.message ?: "error") }) } }
在View層當中引用
package yang.cehome.com.mvvmdemo.view import android.databinding.DataBindingUtil import android.os.Bundle import android.support.v7.app.AppCompatActivity import com.facebook.stetho.okhttp3.StethoInterceptor import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import yang.cehome.com.mvvmdemo.R import yang.cehome.com.mvvmdemo.databinding.ActivityMainBinding import yang.cehome.com.mvvmdemo.model.data.Onclick import yang.cehome.com.mvvmdemo.model.local.AppDatabase import yang.cehome.com.mvvmdemo.model.remote.PostService import yang.cehome.com.mvvmdemo.model.repository.PostRepo import yang.cehome.com.mvvmdemo.viewmodel.OnclikViewModel import yang.cehome.com.mvvmdemo.viewmodel.PostViewModel /** * MVVM 當中的一個V層 將三者聯繫起來 */ class MainActivity : AppCompatActivity() { private lateinit var mBinding: ActivityMainBinding private lateinit var mViewMode: OnclikViewModel private lateinit var mViewMode2: PostViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) /////model val onclick = Onclick("me", 0) ///ViewModel mViewMode = OnclikViewModel(onclick) ///binding val client = OkHttpClient.Builder() .addNetworkInterceptor(StethoInterceptor()) .build() val remote = Retrofit.Builder() .baseUrl("http://www.kuaidi100.com") .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .client(client) .build().create(PostService::class.java) val local= AppDatabase.getInstance(applicationContext).PostDao() val repo = PostRepo(remote, local) ////ViewModel2 mViewMode2 = PostViewModel(repo) mBinding.vm = mViewMode ////binding mBinding.post = mViewMode2 } }
效果
根據上面的內容 我們最後看看效果如何
持久化數據效果
根據Stetho我們也可以看到我們本地的數據庫
利用Stetho查看本地數據
若想了解Stetho請看這篇文章 安卓調試神器-Stetho的使用
最後
至此關於MVVM的數據持久化的工作,我們就完成了。 但是就目前的方法來說,每次都需要寫的模板化的代碼太多了,那麼我們有沒有什麼辦法簡化呢,答案必然是有的。 後面的文章我們會持續介紹到,希望大家持續關注。
問題
我們可以看到,對於ROOM的存儲包括之前用的GreenDao這種類似的存儲都有一個問題,就是根據數據庫對應的格式一個鍵裏面有對應相應的值,那麼當我們的Json返回數據當中包含JsonArray的話,在數據存和取數據就比較麻煩,類似如下
{ "com": "zhongtong", "condition": "F00", "data": [ { "context": "【寧波市】 快件到達 【寧波中轉部】", "ftime": "2018-10-11 20:41:45", "location": "寧波中轉部", "time": "2018-10-11 20:41:45" }, { "context": "【寧波市】 快件離開 【寧波】 發往 【寧波中轉部】", "ftime": "2018-10-11 18:23:24", "location": "寧波", "time": "2018-10-11 18:23:24" }, { "context": "【寧波市】 【寧波】(0574-88014756、0574-88016531、0574-88014575) 的 寧海電商產業園區 (15990572220) 已攬收", "ftime": "2018-10-11 17:14:34", "location": "寧波", "time": "2018-10-11 17:14:34" } ], "ischeck": "1", "message": "ok", "nu": "7510054353700", "state": "3", "status": "200" }
我們直接生成實體,在用Room建庫比較麻煩,以前用的方法是,建一個實體 在存的時候使用
public static String boxing(List<T> List) { if (List == null || List.size() == 0) { return ""; } else { StringBuffer buffer = new StringBuffer(); for (int index = 0; index < payloadList.size(); ++index) { T t = List.get(index); Parcel p = Parcel.obtain(); p.writeValue(t); byte[] bytes = p.marshall(); buffer.append(Base64.encodeToString(bytes, Base64.DEFAULT)); if (index < List.size() - 1) { buffer.append(SPLIT_CHAR); } p.recycle(); } return buffer.toString(); } }
這樣一個JsonArry就存成了一個String
取的時候採用
public static List<T> unBoxing(String listString) { List<T> list = new ArrayList<>(); if (!TextUtils.isEmpty(listString)) { String[] array = listString.split(SPLIT_CHAR); for (String str : array) { Parcel p = Parcel.obtain(); byte[] ba = Base64.decode(str, Base64.DEFAULT); p.unmarshall(ba, 0, ba.length); p.setDataPosition(0); list.add((T) p.readValue(T.class.getClassLoader())); p.recycle(); } } return list; }
這樣取得時候String又變成了List