3).Android Jetpack 一个demo两分钟完全掌握 ViewModel和AndroidViewModel 杀死进程数据存在

23 篇文章 1 订阅
18 篇文章 1 订阅
三个问题,重点原理分析:
  1. ViewModel是如何创建出来的?
  2. 为什么不同的Fragment使用相同的Activity对象来获取ViewModel,可以轻易的实现ViewModel共享?
  3. ViewModel为什么在Activity销毁重建时不会被销毁回收?
 
答案:

这里我们又学到了Activity的两个跟生命周期相关的函数调用:onRetainNonConfigurationInstance和getLastNonConfigurationInstance。

  1. Activity实现了ViewModelStoreOwner接口,创建了ViewModelStore对象。
  2. 当Activity意外销毁时,onRetainNonConfigurationInstance函数被回调,在此函数中对ViewModelStore对象进行了保存。
  3. 当Activity重建时,onCreate方法中会先获取getLastNonConfigurationInstance,如果其中的ViewModelStore对象不为空,就直接引用,不再重新创建ViewModelStore对象了。
横竖平:能够保存数据的原理:ViewModelStore,里面用的hashmap

 
 
 
修改系统语言会发生什么?
进程会被杀死
 

ViewModel横竖屏切换的时候,数据还保留着。不用onSaveInstance方法了

 

ViewModel有下面的两个优点:

  • Activity进行重建的时候,ViewModel的数据不会被回收调用。这时候我们就可以不用通过onSaveInstanceState()方法来进行数据的存储了。而且用onSaveInstanceState()方法为了使Activity能够尽快的重建还只能存储少量的数据进行恢复。
  • Activity中通常会有有那种在其创建的时候获取数据,然后在其销毁的时候释放数据的方法。如果这些放在Activity中的话,在Activity进行重建的时候,会很浪费资源。但是如果方法在ViewModel中的话,Activity的重建将不会导致数据的重复获取。

Fragment间共享数据

在上面ViewMoel的生命周期也提到了 ViewModel只会在Activity存活时,只会创建一次,因此
在同一个Activity中可以在多个Fragment中共享ViewModel中数据。

ViewModel主要是用来存放数据的,

Android中的ViewModel是一个可以用来存储UI相关的数据的类。ViewModel的生命周期会比创建它的Activity、Fragment的生命周期长
 
Demo实战:
上图中,是以平常的方式实现的计数器,当我们旋转屏幕而没有其他处理的时候,计数器的数据丢失了。这是因为屏幕旋转时,我们的activity被销毁重建了,而存放在activity的数据自然也是没有了。
 
    MyViewModel viewModel;
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewModel= ViewModelProviders.of(this).get(MyViewModel.class);

        textView=findViewById(R.id.tv_show);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewModel.num++;
                textView.setText(String.valueOf(viewModel.num));
            }
        });
        textView.setText(String.valueOf(viewModel.num));

    }
}

if(number==null){
    number=new MutableLiveData<>();
    number.setValue(0);
}

使用:
ViewModel不是new出来的
<span style="color:#000000"><span style="color:#cccccc"><code class="language-kotlin"> <span style="color:#cc99cd">val</span> model <span style="color:#67cdcc">=</span> ViewModelProviders.<span style="color:#f08d49">of</span>(activity<span style="color:#67cdcc">!!</span>).<span style="color:#f08d49">get</span>(SharedViewModel<span style="color:#67cdcc">::</span><span style="color:#cc99cd">class</span>.java)</code></span></span>
<span style="color:#000000"><span style="color:#cccccc">
<span style="color:#404040"><code class="language-java"><span style="color:#f8c555">MutableLiveData</span></code></span></span></span>
Databing绑定ViewModel
activityMainBinding=DataBindingUtil.setContentView(this,R.layout.activity_main);
viewModel=ViewModelProviders.of(this,new SavedStateViewModelFactory(this)).get(MyAndroidViewModel.class);
activityMainBinding.setData(viewModel);//databing绑定ViewModel
activityMainBinding.setLifecycleOwner(this);//基类实现了这个监听
 
 
 

AndroidViewModel:防止内存泄漏。

使用ViewModel的时候,需要注意的是ViewModel不能够持有View、Lifecycle、Acitivity引用,而且不能够包含任何包含前面内容的类。因为这样很有可能会造成内存泄漏。

这张图也解释了为什么ViewModel中不能持有ActivityFragmentview的引用。因为Activity在重建后是一个新的对象,如果ViewModel中持有旧对象的引用,这个旧对象可能就等不到释放,造成泄漏。

 

*** 需要注意的是ViewModel类中不应该持有ActivityFragmentview的引用,具体原因后面会讲解释***
如果确实需要,应该使用applicationcontext,或者使用含有上下文的AndroidViewModel

产生的原因:数据永久保存,shareperfece用的话要context.所以产生了AndroidViewModel

那如果需要使用Context对象改怎么办。这时候我们可以给ViewModel一个Application。Application是一个Context,而且一个应用也只会有Application。

我们自己添加Application?其实没必要Google还有一个AndroidViewModel。这是一个包含Application的ViewModel。

下面是一个AndroidViewModel的源码:



下面是一个AndroidViewModel的源码:
<span style="color:#000000"><span style="color:#cccccc"><span style="color:#404040"><code class="language-kotlin"><span style="color:#cc99cd">public</span> <span style="color:#cc99cd">class</span> AndroidViewModel extends ViewModel {
    <span style="color:#cc99cd">@SuppressLint</span>(<span style="color:#7ec699">"StaticFieldLeak"</span>)
    <span style="color:#cc99cd">private</span> Application mApplication;

    <span style="color:#cc99cd">public</span> <span style="color:#f08d49">AndroidViewModel</span>(<span style="color:#cc99cd">@NonNull</span> Application application) {
        mApplication <span style="color:#67cdcc">=</span> application;
    }

    <span style="color:#999999">/**
     * Return the application.
     */</span>
    <span style="color:#cc99cd">@SuppressWarnings</span>(<span style="color:#7ec699">"TypeParameterUnusedInFormals"</span>)
    <span style="color:#cc99cd">@NonNull</span>
    <span style="color:#cc99cd">public</span> <span style="color:#67cdcc"><</span>T extends Application<span style="color:#67cdcc">></span> T <span style="color:#f08d49">getApplication</span>() {
        <span style="color:#999999">//noinspection unchecked</span>
        <span style="color:#cc99cd">return</span> (T) mApplication;
    }
}</code>
</span></span></span>
ViewModelSavedState(进程在后台被杀死数据也能存活)
 
需要添加这个依赖:
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0-rc02'
 
实现:通过private SavedStateHandle handle;
   package com.example.viewmodelsavestate;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.SavedStateHandle;
    public class MyViewModel extends ViewModel {
        private SavedStateHandle handle;
        public MyViewModel(SavedStateHandle handle){
            if(!handle.contains("NUMBER")){
                handle.set("NUMBER",0);
            }
            this.handle = handle;
        }
        public LiveData<Integer>getnumber(){
            return handle.getLiveData("NUMBER");
        }
        public void add(){
            handle.set("NUMBER",(int)handle.get("NUMBER")+1);
        }
    }
public class MainActivity extends AppCompatActivity {

    ActivityMainBinding binding;
    MyViewModel myViewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        myViewModel = new ViewModelProvider(this,new SavedStateViewModelFactory(getApplication(),this)).get(MyViewModel.class);
        binding.setData(myViewModel);
        binding.setLifecycleOwner(this)
 
实战练习:
public class MyAndroidViewModel extends AndroidViewModel {

    SavedStateHandle saveStateHanle

    public MyAndroidViewModel(@NonNull Application application, MutableLiveData<Integer> number, SavedStateHandle saveStateHanle) {
        super(application);
        this.saveStateHanle=saveStateHanle;

    }

    public static final String KEY="dddsfdsafsfds";

    /**
     * 不能为私有
     * @return
     */
    public MutableLiveData<Integer> getNumber() {
        if(!saveStateHanle.contains(KEY)){
            saveStateHanle.set(KEY,0);
        }
        return saveStateHanle.getLiveData(KEY);
    }

    public void add() {
        getNumber().setValue(getNumber().getValue()+1);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值