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/…