初探Architecture Components之ViewModel

原文地址: 官方文档 - ViewModel

Demo地址: Kotlin-Dagger-2-Retrofit-Android-Architecture-Components



ViewModel类用于存储和管理与UI相关的数据,以便UI配置信息更改时保存数据。

应用程序的组件(例如Activity/Fragment)的生命周期由Android系统管理,有可能在内存不足或者某些用户操作来销毁或者重建它们。
由于这些对象可能被操作系统破坏或重新创建,所拥有的任何数据都可能会丢失。例如,当前界面显示用户列表,设备旋转后,重建新的Activity,在新的Activity中必须重新获取用户列表。对于简单的数据而言,可以在onSaveInstanceState()方法中保存,并在onCreate()中的bundle中恢复其数据,但这种处理方式仅适用于少量数据,如UI状态,而不适合大量的数据,例如用户列表。

另一个问题是,Activity/Fragment经需要一些耗时的异步操作,那么就需要管理它们。当被销毁时,为了避免内存泄漏,必然会清除这些异步操作。这样,必定需要大量的维护工作,并且在重新创建对象,更改配置时,需要发出相同的请求,从而浪费资源。

还有一个问题是,Activity/Fragment需要对用户的操作进行反馈,或者处理系统的通信。所有的处理逻辑都写在当前Activity/Fragment类中,从而造成了代码的臃肿。也就是说在一个Activity/Fragment中处理应用程序的所有工作,而不是交由其他类处理。

将数据处理与UI逻辑分离是更容易和更有效的,也就是所谓的解耦。ViewModel作为UI的辅助类,负责管理UI相关的数据。当配置更改时,ViewHold将会自动保存,以便其保存的数据立即用于下一个Activity/Fragment实例。在前面的例子中,ViewModel应该用来获取和保留用户列表信息而不是Activity/Fragment。

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

    private void loadUsers() {
        // do async operation to fetch users
    }
}

那么,可以这样访问数据:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

当Activity重新创建时,它将收到由上一个Activity创建的相同的MyViewModel实例。当Activity销毁时,该框架将调用ViewModel的onCleared()方法,用来清理资源。

注意:由于ViewMode已经超脱于当前Activity/Fragment的生命周期,那么它不能应用View或者任何持有Activity的Contex。如果ViewHold需要应用程序的Context,那么可以继承自AndroidViewModel类,并创建一个将Application(Application继承自Context)实例作为参数的构造函数。

Fragment之间共享数据

非常常见的是,在Activity中,两个或者多个Fragment之间相互通信。这也不算麻烦,自定义回调接口,因为所有的Fragment可以通过Activity将它们绑定在一起。值得考虑的是,必须处理其他Fragment尚未创建或者不可见的情况。

我们可以通过Activity共享一个ViewHold来处理此通信。

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 MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onActivityCreated() {
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onActivityCreated() {
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

值得注意的是,在获取ViewModelProvider时,两个Fragment都使用getActivity(),这意味着它们都将收到相同的SharedViewModel实例,该实例是作用域的是当前Activity。

这种处理方式的好处是:

  • 当前Activity不需要处理任何事情,也不用知道通信的相关内容。
  • 除了SharedViewModel契约之外,Fragment之间并未有直接关联。即使其中一个被销毁,另外一个依然正常工作。
  • 每个Fragment都有自己的生命周期,不受其他Fragment的生命周期的影响。

ViewModel的生命周期

ViewModel的生命周期,将于获取ViewModelProvider时传递的Lifecycle的生命周期相关联。ViewHolder存储在内存中。如果Lifecycle是Activity,那么就是在Activity被销毁时,ViewModel调用onCleared(),释放资源;Lifecycle是Fragment,那么就是在Fragment被分离时,ViewModel调用onCleared(),释放资源;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值