在 support-v7 包中使用 LiveData

Posted 陈蒙_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在 support-v7 包中使用 LiveData相关的知识,希望对你有一定的参考价值。

文章目录

问题复现

当我们在 Activity 中使用 LiveData 时,我们一般会这么用:

public LiveDataDemoActivity extends AppCompatActivity 
    MutableLiveData<Integer> counter;

    @Override
    public void onCreate(Bundle savedInstance) 
        counter = new  MutableLiveData<Integer>();
        counter.setValue(0);
        // ommited code
        counter.observe(this, new Observer<Integer>() 
            @Override
            public void onChanged(@Nullable Integer integer) 
                // update ui
            
        );
    

问题在于,MutableLiveData#observe() 方法的第一个参数必须是 LifecycleOwner 类型的。如果上述代码里面的 AppCompatActivity 是出自 androidx 包的,则是天然支持的,我们看 androidx 里面的 AppCompatActivity:

package androidx.appcompat.app;

// ommited code

public class AppCompatActivity extends FragmentActivity implements AppCompatCallback,
        TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider 

        // ommited code

AppCompatActivity 是继承 FragmentActivity 的:

package androidx.fragment.app;

// ommited code

public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator 

    // ommited code


继续往上追踪:

package androidx.activity;

// ommited code

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner 

// ommited code


可见 androidx.appcompat.app.AppCompatActivity 确实是实现了 LifecycleOwner 接口的,可以直接使用。

解决方案

但是,由于项目工程代码历史较为悠久,很能还没迁移到 androidx 上,可能是 support-v7 里面的 AppCompatActivity。这是我们就没法直接使用 LiveData 了,必须要使其实现 LifecycleOwner 接口才能使用。

假设我们的工程基类是 BaseActivity,则我们需要做的是:


import android.support.v7.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity implements LifecycleOwner 
    private LifecycleRegistry mLifecycleRegistry;

       @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        mLifecycleRegistry = new LifecycleRegistry(this);

        // ommited code
    

    @NonNull
    @Override
    public Lifecycle getLifecycle() 
        return mLifecycleRegistry;
    

在继承 BaseActivity 的 Activity 就可以使用 LiveData 了。
这样就可以在使用 support-v7 库的 AppCompatActivity 的子类 Activity 里面使用 LiveData 了。

工作原理

为什么这样就能正常使用呢?不要在 BaseActivity 里面去重写 onCreate() 等方法去显式的调用 mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) 吗?
那 MutableLiveData 是怎么知道所在页面的生命周期的呢?因为 observe() 方法是在 STARTED 和 RESUMED 的状态才会通知订阅者,只有在能感知到 Activity 声明周期的前提下才能实现上述功能。

关键的是类是 ProcessLifecycleOwnerInitializer、LifecycleDispatcher 和 ReportFragment。ProcessLifecycleOwnerInitializer 是一个 ContentProvider,在其创建的时候会初始化 LifecycleDispatcher:

public class ProcessLifecycleOwnerInitializer extends ContentProvider 
    @Override
    public boolean onCreate() 
        LifecycleDispatcher.init(getContext());
        ProcessLifecycleOwner.init(getContext());
        return true;
    

LifecycleDispatcher 会在 Activity 创建的时候注入 ReportFragment:

   static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks 
        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) 
            if (activity instanceof FragmentActivity) 
                ((FragmentActivity) activity).getSupportFragmentManager()
                        .registerFragmentLifecycleCallbacks(mFragmentCallback, true);
            
            ReportFragment.injectIfNeededIn(activity);
        

ReportFragment 是一个不可见的 Fragment,用于分发事件。而在其内部会根据当前的生命周期变化去通知 LifecycleRegistry:

    private void dispatch(Lifecycle.Event event) 
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) 
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        

        if (activity instanceof LifecycleOwner) 
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) 
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            
        
    

进而,LifecycleRegistry 再去通知 LiveData 当前页面所处的生命周期阶段,所以 LiveData 就知道当前是否为 STARTED 和 RESUMED 状态、是否需要通知订阅者了。

待解疑问

public class ProcessLifecycleOwnerInitializer extends ContentProvider 
    @Override
    public boolean onCreate() 
        LifecycleDispatcher.init(getContext());
        ProcessLifecycleOwner.init(getContext());
        return true;
    

上面代码里面的 getContext() 应该是指当前 Activity,但是 ProcessLifecycleOwnerInitializer 是在 Androidmanifest 里面注册的,应该是只初始化一次的,怎么能绑定到每个 Activity 上的呢?ProcessLifecycleOwner.init(getContext()); 又是做什么的呢?

参考文档

以上是关于在 support-v7 包中使用 LiveData的主要内容,如果未能解决你的问题,请参考以下文章

support-v7是如何将TextView替换为AppCompatTextView的?

RecyclerView使用大全

RecyclerView使用大全

RecyclerView使用大全

RecyclerView具体解释

Android RecycleView使用详解