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的使用
最後
至此關於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