MVVM framework construction (a) – background
The construction of MVVM framework (ii) – project construction
The construction of MVVM framework (three) — network request
MVVM data persistence (I) — ROOM integration
Use and practice of ROOM
In the last article, we introduced the meaning of MVVM persistence and the tool ROOM. Now we will introduce how to use it in our project to achieve data persistence.
Modify the Model layer
Here we need to modify the Model layer by adding a Repository as the data source for the ViewModel layer
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: Fun getPostInfo() = local.getPostInfo(). OnErrorResumeNext { Remote.getpostinfo ().doonSuccess {local.inserttPost(it)}}Copy the code
We can see that the current project structure is:
Modify the data source for our ViewModel layer
We used to use PostService as the data source, now we want to use PostRepo as the data source, we just need to change
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")}}}Copy the code
Reference in the View layer
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 / * * * a V layer of MVVM link three * / 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
}
}
Copy the code
The effect
Let’s take a look at that and see what happens. Okay
According to Stetho we can also see our local database
To learn more about Stetho, read this article about android Debugger Stetho
The last
We are now done with MVVM data persistence. But the current approach requires too much template-based code to be written every time. Is there a way we can simplify this? Surely there is. We will continue to introduce the following articles, I hope you continue to pay attention to.
The problem
As we can see, there is a problem with ROOM storage, including GreenDao, which was used before. According to the corresponding format of the database, there is a corresponding value in one key. Therefore, when our Json returned data contains JsonArray, it will be troublesome to store and fetch data, similar to the following
{
"com": "zhongtong"."condition": "F00"."data": [{"context": "[Ningbo city] Express arrives at [Ningbo Transit Department]"."ftime": "The 2018-10-11 20:41:45"."location": "Ningbo Transit Department"."time": "The 2018-10-11 20:41:45"
},
{
"context": "[Ningbo] Express mail leaves [Ningbo] and is sent to [Ningbo Transit Department]"."ftime": "The 2018-10-11 18:23:24"."location": "Ningbo"."time": "The 2018-10-11 18:23:24"
},
{
"context": "[Ningbo] [Ningbo] (0574-88014756, 0574-88016531, 0574-88014575) Ninghai E-commerce Industrial Park (15990572220) has been acquired"."ftime": "The 2018-10-11 17:14:34"."location": "Ningbo"."time": "The 2018-10-11 17:14:34"}]."ischeck": "1"."message": "ok"."nu": "7510054353700"."state": "3"."status": "200"
}
Copy the code
We directly generate entities, it is more troublesome to use Room to build the library, the previous method is to create an entity to be used when saving
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();
}
returnbuffer.toString(); }}Copy the code
So a JsonArry is stored as a String
Take it when you take it
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;
}
Copy the code
And when I do that String becomes a List again
However, THIS method is not an ideal solution after all. I wonder if there is any good suggestion. Let’s discuss it together.
The project address
Github.com/yang0range/…