美文网首页Android...
Android——JetPack{ViewModel}

Android——JetPack{ViewModel}

作者: So_ProbuING | 来源:发表于2021-09-10 11:52 被阅读0次

    视图与数据模型之间的桥梁ViewModel

    在页面功能较为简单的情况下,我们通常会将UI交互、数据获取等相关的业务逻辑全部写在页面中。但是在页面功能复杂的情况下,这样做就是不合适的。因为这样不符合“单一功能原则”。页面只应该负责处理用户与UI控件的交互,应该将UI与数据相关的业务逻辑隔离开
    为了能够更好地将职能划分,Android为我们提供了ViewModel类,专门用于存放应用程序页面所需的数据


    image.png

    ViewModel的生命周期特性

    由于Android在横竖屏切换,存在数据恢复的问题。现在ViewModel能为我们解决这个问题。ViewModel独立于配置变化。也就是说屏幕旋转所导致的Activity重建,并不会影响ViewModel的生命周期


    ViewModel的生命周期

    由图可以看到,ViewModel的生命周期是贯穿在Activity生命周期的始终的

    ViewModel的基本使用方法

    1. build.gradle 添加依赖
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
    
    1. 写一个继承自ViewModel的类,TimerViewModel
    
    public class TimeViewModel extends ViewModel {
        @Override
        protected void onCleared() {
            super.onCleared();
        }
    }
    

    ViewModel是一个抽象类,其中只有一个onCleared()方法。当ViewModel不再被需要,即与之相关的Activity都被销毁时,该方法会被系统调用

    1. 我们在TimeViewModel中创建一个计时器Timer,每隔1s,通过OnTimerChangeListener通知它的调用者
    public class TimeViewModel extends ViewModel {
        private Timer timer;
        private int currendSecond;
        private OnTimeChangedListener timeChangedListener;
    
        public void setTimeChangedListener(OnTimeChangedListener timeChangedListener) {
            this.timeChangedListener = timeChangedListener;
        }
    
        public void startTiming(){
            if (timer == null) {
                timer = new Timer();
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        currendSecond++;
                        if (timeChangedListener != null) {
                            timeChangedListener.onTimeChanged(currendSecond);
                        }
                    }
                };
            timer.schedule(timerTask,1000,1000);
            }
        }
    
    
        @Override
        protected void onCleared() {
            super.onCleared();
            //release
            timer.cancel();
        }
    
        interface OnTimeChangedListener{
            void onTimeChanged(int second);
        }
    }
    
    1. 在Activity中监听OnTimeChangeListener,并更新UI
      ViewModel的实例化过程,是通过ViewModelProvider来完成的,ViewModelProvider会判断ViewModel是否存在,弱存在则直接返回,若不存在则创建一个viewModel
    public class TimerActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_timer);
            initComponent();
        }
    
        private void initComponent() {
            TextView timeTv = (TextView) findViewById(R.id.tv_second);
            //创建viewModel
            TimeViewModel timeViewModel = new ViewModelProvider(this).get(TimeViewModel.class);
            timeViewModel.setTimeChangedListener(new TimeViewModel.OnTimeChangedListener() {
                @Override
                public void onTimeChanged(int second) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            timeTv.setText("TIME:" + second);
                        }
                    });
                }
            });
            timeViewModel.startTiming();
        }
    }
    

    运行并旋转屏幕,我们可以发现当旋转屏幕导致Activity重建时,计时器并没有停止。这意味着横竖屏状态下的viewModel是同一个,并没有被销毁

    ViewModel的原理

    我们通过new ViewModelProvider(ViewModelStoreOwner owner).get(Class clz)来创建ViewModel对象,而这里我们传入的this,指代当前的Activity。这是因为我们的Activity继承自ComponentActivity,而ComponentActivity默认实现了ViewModelStoreOwner接口

    ComponentActivity
    接口方法getViewModelStore()返回创建的ViewModelStore()
    image.png

    从ViewModelStore的源码可以看出,ViewModel实际上是以HashMap<String,ViewModel>的形式被缓存起来了,ViewModel与页面之间没有直接的关联。通过ViewModelProvider进行关联。当页面需要ViewModel时,会向ViewModelProvider索要,ViewModelProvider会检查该ViewModel是否已经存在于缓存中,若存在则直接返回,若不存在,则实例化一个。因此,Activity由于配置变化导致的销毁重建并不会影响ViewModel,ViewModel是独立于页面存在的

    ViewModel与AndroidViewModel

    由于ViewModel是独立页面的生命周期存在的,所以在使用ViewModel时不要将任何类型的Context或者含有Context引用的对象传入ViewModel。这样会导致内存泄漏,但是如果希望在ViewModel中使用Context,可以使用AndroidViewModel 它继承自ViewModel,并接收Application作为Context,这意味着,它的生命周期和Application是一样的。这就不会造成内存泄漏了

    ViewModel与onSaveInstanceState()方法

    onSaveInstanceState()方法只能保存少量的、并且必须是支持序列化的数据,而ViewModel则没有这个限制。ViewModel能支持页面中所有的数据。

    相关文章

      网友评论

        本文标题:Android——JetPack{ViewModel}

        本文链接:https://www.haomeiwen.com/subject/ygdpwltx.html