天天看點

ViewModel簡單使用(ViewModel + LiveData)

ViewModel官方介紹:

ViewModel類旨在以生命周期意識的方式存儲和管理與UI相關的資料。

ViewModel類允許資料在配置更改(例如螢幕旋轉)後繼續存在。

不做過多贅述。需要了解ViewModel的自行百度。這裡隻說使用。

首先,添加依賴:

//androidx的版本,包含ViewModel和LiveData
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
//非androidx版本
implementation "android.arch.lifecycle:extensions:1.1.1"
           

再然後就是建立 MyViewModel,繼承自 ViewModel:

import android.util.Log;

import androidx.lifecycle.MutableLiveData;

public class MyViewModel extends androidx.lifecycle.ViewModel {

    MutableLiveData<String> mString;
    MutableLiveData<String> msgString;

    public MutableLiveData<String> getString() {
        if (mString == null) {
            mString = new MutableLiveData<>();
        }
        return mString;
    }

    public MutableLiveData<String> getMsgString() {
        if (msgString == null) {
            msgString = new MutableLiveData<>();
        }
        return msgString;
    }

    public void startTask(){
        new Thread(){
            @Override
            public void run() {
                //請求網絡資料、資料庫、加載大圖等。
                //如果在Activity轉屏的時候取消這些任務,那恢複的時候就要重新加載,勢必浪費資源
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //此處用的是LiveData,如果我們不用LiveData可能是通過EventBus之類的把資料傳遞出去的
                msgString.postValue("我是來自3秒後的資料");
                super.run();
            }
        }.start();
    }

    @Override
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
        //做一些資料清理工作
        Log.e("MViewModel","onCleared");
    }
}

           

到此,VM類結束。下面是在activity中用法

在說之前先補充一下擷取ViewModel執行個體的方法:

//在Activity中
mViewModel = ViewModelProviders.of(this).get(MViewModel.class);
//在Fragment中,傳this是擷取和此Fragment綁定的ViewModel,
//傳getActivity則擷取到的是跟activity中的是同一個ViewModel
mViewModel = ViewModelProviders.of(this).get(MViewModel.class);
mViewModel = ViewModelProviders.of(getActivity).get(MViewModel.class);
           

下面是在activity中的具體用法:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.Observer
import com.example.mytestbinder.R
import androidx.lifecycle.ViewModelProviders
import kotlinx.android.synthetic.main.activity_test.*


class TestActivity : AppCompatActivity() {
    var myViewModel: MyViewModel? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)

        //初始化ViewModel
        myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)


        tvLLL.setOnClickListener {

            myViewModel?.startTask()
        }

        //訂閱資料變化
        //對應VM中getmString方法訂閱
        myViewModel?.getmString()?.observe(this,
            Observer<String> { t ->
                tv_test.text = t
            })

        //對應getMsgString方法訂閱
        myViewModel?.getMsgString()?.observe(this,
            Observer<String> { t ->
                messagetv.text = t
            })

        supportFragmentManager.beginTransaction()
            .replace(
                R.id.testLL,
                TestModelFragment(),
                TestModelFragment::class.java.name
            ).commit()

    }
}
           

為了說明ViewModel的作用域,我們再建一個TestFragment

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import com.example.mytestbinder.R;

public class TestModelFragment extends Fragment {
    private Button btModel;
    private MyViewModel mMyViewModel;
    private TextView tvModel;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.model_fragment, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        btModel = view.findViewById(R.id.btModel);
        tvModel = view.findViewById(R.id.tvModel);

        //初始化擷取activity中的ViewModel
        mMyViewModel = ViewModelProviders.of(getActivity()).get(MyViewModel.class);

        //對應VM中getMsgString方法訂閱
        mMyViewModel.getMsgString().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                tvModel.setText(s);
            }
        });

        btModel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //發送消息,getMsgString()為消息發到具體對應的訂閱方法
                mMyViewModel.getMsgString().setValue("Fragment 發送資料");
            }
        });
    }
}
           

通過上面的代碼你會發現ViewModel使用起來非常的簡單,隻需要繼承ViewModel即可,其餘的生命周期之類的就完全不用我們考慮,它自己就能處理。除此之外同一Activity内的Fragment還能不通過Activity直接進行資料互動和共享,實作了真正意義上的解耦。