欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ViewModel+LiveData

程序员文章站 2022-06-07 16:54:24
...

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的生命周期:

ViewModel+LiveData

具体使用

  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官方架构:

ViewModel+LiveData

相关标签: ViewModel