组件化之路 - LiveData + ViewModel一知半解

减法、减法、继续减法,之前记录了一半,最近抽时间再补全一下,仅为个人见解~

Android Architecture Components 架构组件

  • 组件化之路 - Lifecycle一知半解
  • 组件化之路 - LiveData一知半解
  • 组件化之路 - ViewModel一知半解
  • 组件化之路 - LiveData + ViewModel一知半解

因为一直处于小厂的舒适区中,所以除了自我驱动外,一般根本不会接触到近几年的新技术,不过该庆幸的是 “吾虽未齐头奋进,但从未落地不前” ~

近几年 Jetpack 组件库被广泛使用,除去 Kotlincompose 等相关组件外,我们首先应该掌握的还是可兼容Java Lifecycle、LiveData、ViewModel 组件套 ~

    • 基本认知
    • 基础实现
      • 官网示例
      • 自我演练
      • 单串演练
    • 完整Demo
    • 项目实践(明日补入)

基本认知

其实在学习ViewModel组件前,最好是掌握了Lifecycle和LiveData组件,因为在ViewModel中看到了这俩个组件的影子!

每个人的学习方式有所不同,有的喜欢看视频,有的喜欢看blog,有的喜欢看源码,但是根据常规顺序学一样知识的时候,最先看的应该是 官方文档 - LiveData 、官方文档 - ViewModel

我不太清楚别人是如何理解 LiveData、ViewModel 的,我也不知道这么理解对不对 ?

ViewModel 官网介绍:ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

ViewModel 自我理解:保留数据、视图的意外丢失,支持Activity和依赖该Activity的Fragment共享数据源

LiveData 自我理解:可被观察的数据持有类

ViewModel+LiveData 自我理解

  • 涉及到组件的生命周期的范围,一般都用到了Lifecycle
  • ViewModel可分解为View、Model其主要作用是通过数据来驱动视图
  • 数据变化的实时监听,主要是LiveData特性,依托于采用的观察者模式

基础实现

build.gradle 引入依赖

    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:1.1.0"
// alternatively, just ViewModel
//    implementation "android.arch.lifecycle:viewmodel:1.1.0"
// alternatively, just LiveData
//    implementation "android.arch.lifecycle:livedata:1.1.0"

官网示例

注意:此示例为官网中ViewModel的使用示例,尽可借鉴,有个大概印象就好

ViewModel

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

Activity

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

Fragment

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class ListFragment extends Fragment {
    private SharedViewModel model;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), item -> {
           // Update the UI.
        });
    }
}

自我演练

既然都说是ViewModel了,肯定是以model为单元进行演练的,但是最后我也加入了类似LiveData单字符串的调用方式 ~

TestModel

这个很常见,可以理解为 modelbean这样的实体类,没什么特殊的

package com.example.livedata;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc
 */
public class TestModel {
    public TestModel(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public TestModel() {
        super();
    }

    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

TestViewModel

这个类比较关键,是 ViewModel 组件实现的主体类;关于以下俩种实现方式的最终效果是一致的,主要区别在于LiveData和MutableLiveData更新数据时的使用方式,关于具体区别看我上面提到的 LiveData 就好~

实现方式 1:根据官方示例 获取ViewModel时,返回的是LiveData,导致只能通过类内方法进行设值,个人不建议这么使用,虽然实现了出口统一,但是使用起来有点麻烦;不过不能一棒子打死,根据自己场景选取实现方式吧~

package com.example.livedata;

import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc 类似官方的实现方式
 */
public class TestViewModel extends ViewModel {
    private MutableLiveData<TestModel> liveData;
    
    public LiveData<TestModel> getTestViewModel() {
        if (liveData == null) {
            liveData = new MutableLiveData<TestModel>();
        }
        return liveData;
    }
    
    /**
    * 修改数据源
    */
     public void setTestViewModel(TestModel testModel) {
        liveData.postValue(testModel);
    }
    
    /**
     * 可写可不写,主要看需求,用于监听依赖组件的生命周期
     * 由于屏幕旋转导致的Activity重建,该方法不会被调用;
     * 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
     */
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
    }
}:

MainActivity

package com.example.livedata;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;


public class MainActivity extends AppCompatActivity {

    private TestViewModel testViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView mName = findViewById(R.id.tv_test);

        testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
        //接收源,当数据发生改变就会被及时监听到
        testViewModel.getTestViewModel().observe(this, new Observer<TestModel>() {
            @Override
            public void onChanged(TestModel testModel) {
                mName.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
            }
        });

        //发送源,改变数据的地方,此处只是示例而已
        mName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.setTestViewModel(new TestModel("吾名:Live",19));
            }
        });
    }
}

实现方式 2根据对LiveData的掌握,我将获取ViewModel的返回类换MutableLiveData, 主要为了方便我自己的灵活调用> <

package com.example.livedata;

import android.util.Log;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc 只更改获取ViewModel的返回类型
 */
public class TestViewModel extends ViewModel {
    private MutableLiveData<TestModel> mutableLiveData;

    public MutableLiveData<TestModel> getTestViewModel_Mutable() {
        if (mutableLiveData == null) {
            mutableLiveData = new MutableLiveData<TestModel>();
        }
        return mutableLiveData;
    }

    /**
     * 由于屏幕旋转导致的Activity重建,该方法不会被调用
     * 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
     */
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
    }
}

MainActivity

package com.example.livedata;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;


public class MainActivity extends AppCompatActivity {

    private TestViewModel testViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView mName = findViewById(R.id.tv_test);

        testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
        //接收源,当数据发生改变就会被及时监听到
        testViewModel.getTestViewModel_Mutable().observe(this, new Observer<TestModel>() {
            @Override
            public void onChanged(TestModel testModel) {
                mName.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
            }
        });

        //发送源,改变数据的地方,此处只是示例而已
        mName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.getTestViewModel_Mutable().postValue(new TestModel("吾名:Live",19));
            }
        });
    }
}

单串演练

上方主要是关于一个model的监听,这里就是仅观察一个字符串的案例,闲的没事儿尝试后记录一下,和LiveData的基本功能有点一样 ~

TestViewModel

package com.example.livedata;

import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc
 */
public class TestViewModel extends ViewModel {
    private MutableLiveData<String> stringMutableLiveData;

    MutableLiveData<String> getAlone() {
        if (stringMutableLiveData == null) {
            stringMutableLiveData = new MutableLiveData<>();
        }
        return stringMutableLiveData;
    }

    /**
     * 由于屏幕旋转导致的Activity重建,该方法不会被调用
     * 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
     */
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.e("tag","只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
    }
}

MainActivity

package com.example.livedata;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;


public class MainActivity extends AppCompatActivity {

    private TestViewModel testViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView mName = findViewById(R.id.tv_alone);

        testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
        //接收源,当数据发生改变就会被及时监听到
        testViewModel.getAlone().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String data) {
                mAlone.setText(data);
            }
        });

        //发送源,改变数据的地方,此处只是示例而已
        mAlone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.getAlone().postValue("小小笑话可笑可笑");
            }
        });
    }
}

完整Demo

TestModel

package com.example.livedata;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc
 */
public class TestModel {
    public TestModel(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public TestModel() {
        super();
    }

    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

TestViewModel

package com.example.livedata;

import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

/**
 * @author MrLiu
 * @date 2021/12/21
 * desc
 */
public class TestViewModel extends ViewModel {
    private MutableLiveData<TestModel> liveData;
    private MutableLiveData<TestModel> mutableLiveData;
    private MutableLiveData<String> stringMutableLiveData;

    public LiveData<TestModel> getTestViewModel() {
        if (liveData == null) {
            liveData = new MutableLiveData<TestModel>();
        }
        return liveData;
    }

    public MutableLiveData<TestModel> getTestViewModel_Mutable() {
        if (mutableLiveData == null) {
            mutableLiveData = new MutableLiveData<TestModel>();
        }
        return mutableLiveData;
    }

    public void setTestViewModel(TestModel testModel) {
        liveData.postValue(testModel);
    }

    MutableLiveData<String> getAlone() {
        if (stringMutableLiveData == null) {
            stringMutableLiveData = new MutableLiveData<>();
        }
        return stringMutableLiveData;
    }
    
    /**
     * 由于屏幕旋转导致的Activity重建,该方法不会被调用
     * 只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源
     */
    @Override
    protected void onCleared() {
        super.onCleared();
        Log.e("tag", "只有ViewModel已经没有任何Activity与之有关联,系统则会调用该方法,你可以在此清理资源");
    }
}

MainActivity

package com.example.livedata;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;


public class MainActivity extends AppCompatActivity {

    private TestViewModel testViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView mTest = findViewById(R.id.tv_test);
        TextView mAlone = findViewById(R.id.tv_alone);

        testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
//       数据监听
        testViewModel.getTestViewModel_Mutable().observe(this, new Observer<TestModel>() {
            @Override
            public void onChanged(TestModel testModel) {
                mTest.setText("姓名:" + testModel.getName() + " - 年龄:" + testModel.age);
            }
        });

        testViewModel.getAlone().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String data) {
                mAlone.setText(data);
            }
        });

//      数据发送
        mTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.setTestViewModel(new TestModel("吾名:Live", 19));
            }
        });

        mTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.getTestViewModel_Mutable().postValue(new TestModel("吾名:Live", 19));
            }
        });

        mAlone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testViewModel.getAlone().postValue("小小笑话可笑可笑");
            }
        });
    }
}

项目实践(明日补入)

前俩年有幸重新搭过一次项目框架,当时的 MVVM框架 采用的就是 JetPack 内的组件

这里记录一份我在项目中使用 ViewVodel + LiveData 的伪代码

你可能感兴趣的:(Android组件化之路,Android进阶之路,Android,Jetpack,LiveData,ViewModel)