ViewModel

ViewModel是用来保存和操作UI相关的数据的,这样即使configuration发生改变,数据仍然可以存在。

引入ViewModel的原因有三点:

  1. Activity和Fragment等App组件的生命周期都是由系统控制的,是开发者不可控的,保存在其中的数据就有丢失的危险。虽然可以通过onSaveInstanceState()来保存数据,可是这个回调只适合用来保存少量数据比如UI状态,对于一些大量数据比如列表数据就不合适了。

  2. 而且Activity和Fragment中都可能进行一些异步操作,这就需要在销毁的时候去清空回调避免内存泄露。或者界面重建后还要重新获取数据,也会浪费资源。

  3. UI控制器本身就负责处理用户交互和系统交互,如果还需要处理数据问题,就会导致职责过多。

所以有必要从UI控制器中抽离出数据的控制权。Lifecycle库提供了ViewModel类用来给UI提供数据。ViewModel不受configuration改变的影响。

ViewModel的示例:

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
    }
}

Activity中的使用:

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所创建的ViewModel。如果该Activity销毁了,ViewModel的onCleared()会被调用,清空资源。

注意:因为ViewModel独立于Activity和Fragment,所以不能引用任何View,或者任何引用了Context 的对象。如果ViewModel需要一个Application类型的Context,可以继承于AndroidViewModel类,构造方法中会有一个Application对象。

在Fragment间分享数据

Fragment间经常需要分享数据,通常是定义接口,然后通过Activity联系在一起。但是Fragment间的生命周期又可能存在不同步,问题就变得比较复杂了。

假设现在有个列表Fragment,还有一个内容Fragment,点击列表Fragment某一项会更新内容Fragment,使用ViewModel可以比较方便地处理数据问题。可以通过Activity获取同一个ViewModel:

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 onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

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

这样做的好处是:

  • Activity不用再负责两个Fragment之间的联系
  • Fragment只需要知道ViewModel,不需要知道其他的Fragment,耦合性降低
  • 每个Fragment的生命周期相互独立互不影响。

ViewModel的生命周期

这里写图片描述

ViewModel和SavedInstanceState

ViewModel在Activity的configuration改变过程中可以保持数据不变,但是如果系统把应用杀死掉就没办法了。

如果用户长时间离开应用再进来,应用进程可能已经被系统杀掉了,此时系统会负责恢复之前保存的SavedInstanceState。在onSaveInstanceState()中保存的数据是放在系统进程内存中的,Android系统只允许存放少量的数据,所以最好不要存放一些自定义类的对象进去,可以把自定义对象保存到数据库中,onSaveInstanceState中只保留对象的某个字段比如id,然后再使用ViewModel根据这个id去获取完整的数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值