ViewModel+LiveData

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangcheng_/article/details/79385417

Android在前段时间正式发布 Android 架构组件 1.0 稳定版,里面包含Lifecycles,LiveData,ViewModel,Room。这里主要记录一下LiveData和ViewModel配合使用。

LiveData

LiveData 是一款基于观察者模式的可感知生命周期的核心组件。LiveData 为界面代码 (Observer)的监视对象 (Observable),当 LiveData 所持有的数据改变时,它会通知相应的界面代码进行更新。同时,LiveData 持有界面代码 Lifecycle 的引用,这意味着它会在界面代码(LifecycleOwner)的生命周期处于 started 或 resumed 时作出相应更新,而在 LifecycleOwner 被销毁时停止更新。通过 LiveData,开发者可以方便地构建安全性更高、性能更好的高响应度用户界面

使用LiveData的好处
  • 保证你的UI 能根据数据状态发生改变
  • 不会有内存泄漏
  • 不会因为Activity的stop造成crashes
  • 不用手动去控制生命周期
  • 永远保证数据更新

ViewModel

ViewModel 将视图的数据和逻辑从具有生命周期特性的实体(如 Activity 和 Fragment)中剥离开来。直到关联的 Activity 或 Fragment 完全销毁时,ViewModel 才会随之消失,也就是说,即使在旋转屏幕导致 Fragment 被重新创建等事件中,视图数据依旧会被保留。ViewModels 不仅消除了常见的生命周期问题,而且可以帮助构建更为模块化、更方便测试的用户界面。

ViewModel的作用和好处
  • Activity、Fragment存活期间的数据存储;
  • 独立或与LiveData配合实现代码解耦;
ViewModel的生命周期

ViewModel的生命周期与Lifecycle同步,当Activity /Fragment超出Lifecycle范围(并不是onDestroy()回调),ViewModel连同其包含的数据一起被销毁了。
Activity退栈后(Fragment则是与Activity解除关系后),ViewModel就解除引用关系,准备被系统回收了。下面这张图片更直观的展示了ViewModel的生命周期:

image

具体使用

  1. 引入ViewModel和LiveData

    在build.gradle中添加编译lifecycle.extensions module,该module同时包含ViewModel和LiveData:

compile('android.arch.lifecycle:extensions:1.0.0')
  1. 构造ViewModel
    借用官方提供的例子,去获取一个用户的数据,这里直接引入LiveData构造一个ViewModel.
public class UserProfileViewModel extends ViewModel {
    ...
    private User user;
    private LiveData<User> user;
    public LiveData<User> getUser() {
        return user;
    }
}
  1. 获取数据

    首先通过ViewModelProviders和Activity / Fragment获取ViewModelProvider;
    然后根据ViewModelProvider和自定义ViewModel类获取自定义ViewModel对象;

public class UserProfileFragment extends Fragment {
    private static final String UID_KEY = "uid";
    private UserProfileViewModel viewModel;

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        String userId = getArguments().getString(UID_KEY);
         viewModel.getUser().observe(this, user -> {
            // update UI
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater,
                @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.user_profile, container, false);
    }
}

进行到这一步,基本实现了每一次User数据更新就会回掉刷新UI界面。而且并不需要去实现Fragment的onStop()方法来停止观察数据。因为LiveData是一个有生命周期意识的组件,它不需要我们去手动的停止,而且会在onDestroy()中自动的remove 掉这个观察事件。

另外也并不需要去管屏幕的旋转,因为当屏幕旋转的时候ViewModel会自动保存下当前Fragment的数据和状态。

经过上面的步骤已经将ViewModel和fragment关联起来了,但是并没有真正的通过ViewModel去获取数据。下面记录一下如何通过Retrofit 去获取数据:

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<User> getUser(@Path("user") String userId);
}

新建一个UserRepository

public class UserRepository {
    private Webservice webservice;
    // ...
    public LiveData<User> getUser(int userId) {
        // This is not an optimal implementation, we'll fix it below
        final MutableLiveData<User> data = new MutableLiveData<>();
        webservice.getUser(userId).enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                // error case is left out for brevity
                data.setValue(response.body());
            }
        });
        return data;
    }
}

就像官方描述的UserRepository并不是必须的,把它抽象出来,这样ViewModel就不知道数据是通过Webservice来获取的,好处就是which means we can swap it for other implementations as necessary.

最后将UserRepository和ViewModel关联起来,修改ViewModel:

public class UserProfileViewModel extends ViewModel {
    private LiveData<User> user;
    private UserRepository userRepo;

    @Inject // UserRepository parameter is provided by Dagger 2
    public UserProfileViewModel(UserRepository userRepo) {
        this.userRepo = userRepo;
    }

    public void init(String userId) {
        if (this.user != null) {
            // ViewModel is created per Fragment so
            // we know the userId won't change
            return;
        }
        user = userRepo.getUser(userId);
    }

    public LiveData<User> getUser() {
        return this.user;
    }
}

总结

就这样一个完整的ViewModel+LiveData的例子就完成了。

ViewModel+LiveData可以很方便的抽象出数据层和业务层,快速解耦。
通过Demo,以及LiveData、ViewModel同处一个module,可以看出官方非常建议两者搭配使用。再配合以往的Data-Binding,可以快速搭建起一套简易的MVVM业务体系。

最后通过一张图可以大概的了解下Android官方架构:

image

展开阅读全文

没有更多推荐了,返回首页