private LiveData user;
public LiveData getUser() {
return user;
}
}
然后将UserProfileFragment修改如下,观察数据并更新UI:
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel.getUser().observe(this, user -> {
// update UI
});
}
一旦用户数据更新,onChanged回调将被调用然后UI会被刷新。
如果你熟悉一些使用观察者模式第三方库,你会觉得奇怪,为什么没有在Fragment的onStop()方法中将观察者移除。对于LiveData来说这是没有必要的,因为它是生命周期感知的,这意味着如果UI处于不活动状态,它就不会调用观察者的回调来更新数据。并且在onDestroy后会自动移除。
我们也不需要处理任何视图重建(如屏幕旋转)。ViewModel会自动恢复重建前的数据。当新的视图被创建出来后,它会接收到与之前相同的ViewModel实例,并且观察者的回调会被立刻调用,更新最新的数据。这也是ViewModel为什么不能直接引用视图对象,因为它的生命周期长于视图对象。
获取数据
现在我们将视图和模型连接起来,但是模型该怎么获取数据呢?在这个例子中,我们假设使用REST API从后台获取。我们将使用Retrofit来向后台请求数据。
我们的retrofit类Webservice如下:
public interface Webservice {
/**
- @GET declares an HTTP GET request
- @Path(“user”) annotation on the userId parameter marks it as a
- replacement for the {user} placeholder in the @GET path
*/
@GET("/users/{user}")
Call getUser(@Path(“user”) String userId);
}
如果只是简单的实现,ViewModel可以直接操作Webservice来获取用户数据。虽然这样可以正常工作,但你的应用无法保证它的后续迭代。因为这样做将太多的责任让ViewModel来承担,这样就违反类之前讲到的分层原则。又因为ViewModel的生命周期是绑定在Activity和Fragment上的,所以当UI被销毁后如果丢失所有数据将是很差的用户体验。所以我们的ViewModel将和一个新的模块进行交互,这个模块叫Repository。
Repository模块负责处理数据。它为应用程序的其余部分提供了一个干净的API。他知道在数据更新时从哪里获取数据和调用哪些API调用。你可以将它们视为不同数据源(持久性模型,Web服务,缓存等)之间的中介者。
UserRepository类如下:
public class UserRepository {
private Webservice webservice;
// …
public LiveData getUser(int userId) {
// This is not an optimal implementation, we’ll fix it below
final MutableLiveData data = new MutableLiveData<>();
webservice.getUser(userId).enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
// error case is left out for brevity
data.setValue(response.body());
}
});
return data;
}
}
虽然repository模块看上去没有必要,但他起着重要的作用。它为App的其他部分抽象出了数据源。现在我们的ViewModel并不知道数据是通过WebService来获取的,这意味着我们可以随意替换掉获取数据的实现。
管理组件间的依赖关系
上面这种写法可以看出来UserRepository需要初始化Webservice实例,这虽然说起来简单,但要实现的话还需要知道Webservice的具体构造方法该如何写。这将加大代码的复杂度,另外UserRepository可能并不是唯一使用Webservice的对象,所以这种在内部构建Webservice实例显然是不推荐的,下面有两种模式来解决这个问题:
- **依赖注入:**依赖注入允许类定义它们的依赖关系而不构造它们。在运行时,另一个类负责提供这些依赖关系。我们建议在Android应用程序中使用Google的Dagger 2库实现依赖注入。Dagger 2通