soapgu/PlayPen

LiveData初次登场

Opened this issue · 0 comments

  • 前言

    其实在学习过程中一直有接触到,但是始终是似懂非懂。对这个组件也没有一个初步的定位和理解。
    我第一次想用LiveData的时候是在学习Binding特性的时候。但是对于数据的变化可以由Observable 代劳,LiveData并不是唯一的选择。这样就会产生一个疑惑,那么LiveData是为Binding而生的吗,那么既然没有LiveData也可以做Binding。那么LiveData的真正价值在哪里。我回答不了这个问题。只能暂时搁置,暂缓使用。

  • LiveData出道

我在实际使用过程中出现这样的场景。我想要在某个ViewModel中执行跳转到其他Activity的Intent操作,但是这个操作是不被Android设计者鼓励

  1. Intent的生成需要在Activity内执行,startActivity这个API本身就是Activity的成员函数
  2. ViewModel禁止拥有Activity的引用,MVVM界的共识,本身解耦分家的两个部件又搅合在一起,本身就是违法架构原则。其二,Activity的生命周期要比ViewModel要短,增加引用还会引起不必要的内存泄露

迫于无奈我只能写出这样别扭的诡异的代码

protected void onCreate(Bundle savedInstanceState) {
        Logger.i( "---Create MainActivity----" );
        super.onCreate(savedInstanceState);
        HomeViewModel viewModel = new ViewModelProvider(this,
                ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication()))
                .get(HomeViewModel.class);
        ActivityMainBinding binding  = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setDatacontext( viewModel );
        binding.searchButton.setOnClickListener( v -> {
            Intent intent = new Intent(this, SearchActivity.class);
            startActivity(intent);
        } );
    }

感觉就是革命不彻底的表现

LiveData终于横空出世

  • 特性1 变化

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者

这是数据变化,和个特性和Observable有重合

  • 特性2 根据观察者生命周期推送,释放退订变化

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。
您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。

这个特性才是关键,这里已经很明确说了,就是为Activity 和 Fragment量身定做的,目的就是建立起UI Control层(Activity,Fragment)和ViewModel的联系

  • LiveData家族(相关Package)

dependencies {
    def lifecycle_version = "2.2.0"

    // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // use -ktx for Kotlin
    // alternatively - just LiveData
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData). Some UI
    //     AndroidX libraries use this lightweight import for Lifecycle
    implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"

    annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin
    // alternately - if using Java8, use the following instead of lifecycle-compiler
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

    // optional - ReactiveStreams support for LiveData
    implementation "androidx.lifecycle:lifecycle-reactivestreams:$lifecycle_version" // use -ktx for Kotlin

    // optional - Test helpers for LiveData
    testImplementation "androidx.arch.core:core-testing:$lifecycle_version"
}
  • LiveData使用示例

在build.gradle中添加
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

在MainViewModel.java中加入LiveData字段

private MutableLiveData<Class<?>> targetActivity;

public MutableLiveData<Class<?>> getTargetActivity() {
        if( targetActivity == null )
            targetActivity = new MutableLiveData<>();
        return targetActivity;
    }

泛型类代表传入显示Activity的类型

public void GoToRecognizeActivity()
    {
        this.targetActivity.setValue(RecognizeActivity.class);
    }

按钮触发的逻辑就是设置LiveData的值,把要跳转的Activity类型通知出去

MainActivity.java中订阅LiveData

 viewModel.getTargetActivity().observe(this, t->{
            Intent intent = new Intent(this,t);
            startActivity(intent);
        });

这样清晰的多了,Activity里面还是做startActivity的事情,ViewModel管好业务和数据逻辑,大家各司其职。

  • LiveData的副产品 绑定通知

  class ViewModelActivity extends AppCompatActivity {
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           // Inflate view and obtain an instance of the binding class.
           UserBinding binding = DataBindingUtil.setContentView(this, R.layout.user);

           // Specify the current activity as the lifecycle owner.
           binding.setLifecycleOwner(this);
       }
   }

注意如果把 LiveData用做绑定需要加上 binding.setLifecycleOwner(this);