public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String userId = getArguments().getString(UID_KEY);
viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);
viewModel.init(userId);
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.user_profile, container, false);
}
}
现在,我们已经有了三个代码块,那么我们如何将它们联系在一起呢?毕竟,当给 ViewModel 的用户字段设值后,我们需要一种方法来通知用户界面,这就是 LiveData 类的作用。
LiveData 是一个可观察的数据持有者。它允许应用程序中的组件观察 LiveData 对象的更改,但不会在它们之间创建明确的和严格的依赖关系路径。 LiveData 还会关联 app组件(activities, fragments, services) 的生命周期状态,并做出合适的事情来防止内存泄漏。
注意:如果你已经在使用类似 RxJava 或 Agera 的库 ,则可以继续使用它们而不是LiveData。但是,当你使用它们或其他方式时,请确保正确处理生命周期,以便在相关的LifecycleOwner 停止时暂停数据流,并在销毁 LifecycleOwner 时销毁数据流。你还可以添加 android.arch.lifecycle:reactivestreams 以将 LiveData 与其他的响应流库(例如RxJava2)一起使用。
现在我们用 LiveData 替换 UserProfileViewModel 中的 User字段,以便在数据更新时通知 Fragment。最主要的是,LiveData 是生命周期感知的,并且在不在需要时,它将自动清理引用。
public class UserProfileViewModel extends ViewModel {
…
private User user;
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 来说是没有必要的,因为它是生命周期感知的,这意味着它不会调用回调,除非Fragment 处于 活动状态(已收到 onStart() 但未收到 onStop())。当 fragment 收到 onDestroy() 时,LiveData也将自动移除观察者 。
对于配置变化(例如,用户旋转屏幕)我们也没有做任何特殊的处理。当配置改变时,ViewModel 会自动恢复,所以一旦新的 Fragment 生效,它将接收到相同的 ViewModel实例,并且 ViewModel 的回调将立即被当前数据调用,这就是 ViewModels 为什么不应该直接引用 Views 的原因。他们可以比 View的生命周期更持久。想了解更多信息的请查看 The lifecycle of a ViewModel 。
获取数据
现在我们已经将 ViewModel 关联到了 Fragment,但是 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);
}
ViewM