Android 自定义Livedata使用示例解析

目录
  • 前言
  • Livedata分析
  • 自定义Livedata
  • 总结

前言

我们在开发中在使用MVVM的情况下经常会配合livedata来达到快速开发的效果,但是一般都是在activity或者fragment中去使用,我今天想介绍一种自定义的方式,如果你有复杂的自定义View或者某些场景,也可以使用livedata来达到一个很不错的效果。

Livedata分析

我们平时使用livedata都会在activity或者fragment中使用,配合 Lifecycle就不用管理生命周期什么的了,所以一般以activity或fragment作为view层(当然service内也有相应的封装)。

viewmodel层,继承lifecycler的ViewModel

var data : MutableLiveData<Int> = MutableLiveData()
fun test(){
  data.value = 1
}

view层

var viewmodel = ViewModelProvider(this).get(TestViewModel::class.java)
viewmodel?. data?.observe(this, Observer {
            // todo
        })

一般来说就这样写嘛,也不用考虑注销什么的,它自己内部帮你实现,很方便,but 也只能在activity或者fragment中能这样写

假如在view中这样写,传this的地方会报错,为什么呢,我们可以看看view层的两个this传的是什么。
创建ViewModelProvider时传

public ViewModelProvider(@NonNull ViewModelStoreOwner owner)

调用observe方法时传

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)

可以看到一个是ViewModelStoreOwner,另一个是LifecycleOwner,并不是同一个东西

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}
public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

我们看看Activity内部是怎么封装的

public class FragmentActivity extends ComponentActivity implements
        ViewModelStoreOwner,
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator
public class ComponentActivity extends Activity
        implements LifecycleOwner, KeyEventDispatcher.Component

看接口的实现

    public ViewModelStore getViewModelStore() {
        ......
        if (mViewModelStore == null) {
            ......
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

看到内部是有引用一个ViewModelStore对象
在onDestroy时

    protected void onDestroy() {
        super.onDestroy();
        if (mViewModelStore != null && !isChangingConfigurations()) {
            mViewModelStore.clear();
        }
        ......
    }

可以看出实现ViewModelStoreOwner接口就是持有ViewModelStore对象,并保证它的创建和销毁,而它的内部会持有viewmodel

public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }
    final ViewModel get(String key) {
        return mMap.get(key);
    }
    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

那这个ViewModelStore在哪里使用呢,我们看到FragmentActivity这里只做了创建和销毁,并没有执行put和get方法,我们深入去看可以发现put/get是在ViewModelProvider中调用。这也对应了我们最初的初始化ViewModel的方法

var viewmodel = ViewModelProvider(this).get(TestViewModel::class.java)

所以很容易能看出ViewModelStore就是用来管理viewmodel的。
接下来我们看LifecycleOwner,在activity的实现这个接口的方法

    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

看得出返回LifecycleRegistry对象,LifecycleRegistry就是Lifecycle的实现类,在Activity中存在调用方法

// 有很多地方有调addObserver方法
getLifecycle().addObserver(new LifecycleEventObserver() {......})
// 在这里调setCurrentState方法
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        Lifecycle lifecycle = getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);
        }
        super.onSaveInstanceState(outState);
        mSavedStateRegistryController.performSave(outState);
    }

值得注意的是LifecycleRegistry中的setCurrentState方法和handleLifecycleEvent方法

    @MainThread
    public void setCurrentState(@NonNull State state) {
        moveToState(state);
    }
    public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        State next = getStateAfter(event);
        moveToState(next);
    }

看得出它们最终都是调用moveToState,调用handleLifecycleEvent只是为了把 Lifecycle.Event转成State

    private void moveToState(State next) {
        if (mState == next) {
            return;
        }
        mState = next;
        ......
    }

Lifecycle的代码就不分析了,这边主要讲Livedata。
同样能看出FragmentActivity有调用handleLifecycleEvent

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        mFragments.dispatchCreate();
    }
   @Override
    protected void onStart() {
        ......
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        mFragments.dispatchStart();
    }
    protected void onResumeFragments() {
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        mFragments.dispatchResume();
    }
    @Override
    protected void onStop() {
        ......
        mFragments.dispatchStop();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mFragments.dispatchDestroy();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    }

再看看另一个LifecycleOwner的实现,Service,这个Service叫LifecycleService

public class LifecycleService extends Service implements LifecycleOwner

它内部引用一个ServiceLifecycleDispatcher对象,而这个对象内部引用LifecycleRegistry。

    /**
     * Must be a first call in {@link Service#onCreate()} method, even before super.onCreate call.
     */
    public void onServicePreSuperOnCreate() {
        postDispatchRunnable(Lifecycle.Event.ON_CREATE);
    }
    /**
     * Must be a first call in {@link Service#onBind(Intent)} method, even before super.onBind
     * call.
     */
    public void onServicePreSuperOnBind() {
        postDispatchRunnable(Lifecycle.Event.ON_START);
    }
    /**
     * Must be a first call in {@link Service#onStart(Intent, int)} or
     * {@link Service#onStartCommand(Intent, int, int)} methods, even before
     * a corresponding super call.
     */
    public void onServicePreSuperOnStart() {
        postDispatchRunnable(Lifecycle.Event.ON_START);
    }
    /**
     * Must be a first call in {@link Service#onDestroy()} method, even before super.OnDestroy
     * call.
     */
    public void onServicePreSuperOnDestroy() {
        postDispatchRunnable(Lifecycle.Event.ON_STOP);
        postDispatchRunnable(Lifecycle.Event.ON_DESTROY);
    }
    @NonNull
    public Lifecycle getLifecycle() {
        return mRegistry;
    }
    static class DispatchRunnable implements Runnable {
        private final LifecycleRegistry mRegistry;
        final Lifecycle.Event mEvent;
        private boolean mWasExecuted = false;
        DispatchRunnable(@NonNull LifecycleRegistry registry, Lifecycle.Event event) {
            mRegistry = registry;
            mEvent = event;
        }
        @Override
        public void run() {
            if (!mWasExecuted) {
                mRegistry.handleLifecycleEvent(mEvent);
                mWasExecuted = true;
            }
        }
    }

在外层调用

 @CallSuper
    @Override
    public void onCreate() {
        mDispatcher.onServicePreSuperOnCreate();
        super.onCreate();
    }
    @CallSuper
    @Nullable
    @Override
    public IBinder onBind(@NonNull Intent intent) {
        mDispatcher.onServicePreSuperOnBind();
        return null;
    }
    @SuppressWarnings("deprecation")
    @CallSuper
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        mDispatcher.onServicePreSuperOnStart();
        super.onStart(intent, startId);
    }
    // this method is added only to annotate it with @CallSuper.
    // In usual service super.onStartCommand is no-op, but in LifecycleService
    // it results in mDispatcher.onServicePreSuperOnStart() call, because
    // super.onStartCommand calls onStart().
    @CallSuper
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    @CallSuper
    @Override
    public void onDestroy() {
        mDispatcher.onServicePreSuperOnDestroy();
        super.onDestroy();
    }
    @Override
    @NonNull
    public Lifecycle getLifecycle() {
        return mDispatcher.getLifecycle();
    }

那么我们得出一个结论,要实现LifecycleOwner,主要就是自己去使用handleLifecycleEvent方法去设置生命周期。

那么这里有个问题,如果我有个Service继承LifecycleService,它能直接快速的使用Livedata吗,当然不能,因为LifecycleService只实现了LifecycleOwner,并没有实现ViewModelStoreOwner

自定义Livedata

按照上面Activity的源码,我们知道,要实现Livedata,主要分为两个步骤:

  • 1. 实现ViewModelStoreOwner并完成ViewModelStore的创建和销毁
  • 2. 实现LifecycleOwner并手动设置生命周期其实现在网上也有很多人讲在自定义View上使用Livedata,我这里就做点不同的,我在window上去实现,其实原理都是一样的。
class MyWindow internal constructor(val context: Context) : AbstractWindow(), LifecycleOwner,
    ViewModelStoreOwner {
    private var mViewModel : MyViewModel? = null
    private var mViewModelStore: ViewModelStore ?= null
    private val mRegistry = LifecycleRegistry(this)
  fun init(){
  // todo一些初始化操作
   mRegistry.currentState = Lifecycle.State.CREATED
   mViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
   mViewModel?.data?.observe(this, Observer {
            ......
        })
  }
  fun show(){
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    mWindowManager.addView(mView, getLayoutParams());
  }
  fun close(){
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
    mWindowManager.removeViewImmediate(mView);
  }
    override fun getLifecycle(): Lifecycle {
        return mRegistry
    }
    override fun getViewModelStore(): ViewModelStore {
        if (mViewModelStore == null){
            mViewModelStore = ViewModelStore()
        }
        return mViewModelStore!!
    }
    fun onDestroy(){
     mRegistry?.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
     mViewModelStore?.clear()
    }

这样就能在非activity/fragment的view层中实现livedata功能。

总结

自定义livedata其实没有太大的难度,这是一个开发的过程,你想在一些地方去使用官方封装好的框架,可以先去看看它是怎么做的,再自己进行一个二次封装,就能实现那么一个效果,比如这里的自定义View或者Window使用Livadata。

以上就是Android 自定义Livedata使用示例解析的详细内容,更多关于Android 自定义Livedata的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android开发中用Kotlin编写LiveData组件教程

    目录 1.简单使用 2.map和switchMap LiveData是Jetpack提供的一种响应式编程组件,它可以包含任何类型的数据,并在数据发生变化的时候通知给观察者.也就是说,我们可以将数据使用LiveData来包装,然后在Activity中去观察它,就可以主动将数据变化通知给Activity了. 1.简单使用 class MainViewModel(countReserved:Int) : ViewModel() { /*当外部调用counter变量时,实际上获得的就是_counter的

  • Android Jetpack 狠活Lifecycles与LiveData使用详解

    目录 前言 正篇 结语 前言 今天在工作时,测试突然提了一个Bug给我,要求我将APP中某活动页面的UI界面要根据用户在由此页面跳转的下个页面操作,在返回时要实时更新. 在检查代码时,发现我已经对界面可变数据用LiveData去观测,但由于页面变化后并没有重新初始化UI,所以我放在初始化UI的请求根本没有起效,如上图所示例子,在进入下一个页面如若关闭开关,返回时无法及时更新,于是我便想到了安卓科技与狠活Lifecycles,去监听onResume,在resume时用livedata去post数据

  • Android Jetpack组件支持库DataBinding与ViewModel与LiveData及Room详解

    目录 一.官方推荐的Jetpack架构 二.添加依赖 三.创建Repository 四.创建ViewModel 五.activity中使用 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle 一.官方推荐的Jetpack架构 ViewModel是介于View(视图)和Model(数据模型)之间的中间层,能够使视图和数据分离,又能提供视图和数据之间的通信. LiveData是一个能够在ViewModel中数据发生变化时通知页面刷

  • Android Jetpack组件库LiveData源码深入探究

    目录 前言 一.LiveData 二.使用案例 三.LiveData 实现原理 四.LiveData 相关源码 五.LiveData分发问题 Android Jetpack之ViewModel.LiveData Android Jetpack之LifeCycle Android Jetpack之DataBinding+ViewModel+LiveData+Room 前言 Jetpack是一个由多个技术库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种Android版本和设备中一致

  • Android开发Jetpack组件ViewModel与LiveData使用讲解

    目录 一.ViewModel 1.解决的问题 2.注意点事项 3.ViewModel案例 二.LiveData 1.viewmodel+livedata使用案例 2.viewmodel+livedata Android Jetpack之LifeCycle 一.ViewModel ViewModel是介于View(视图)和Model(数据模型)之间的中间层,能够使视图和数据分离,又能提供视图和数据之间的通信.如图所示: 1.解决的问题 屏幕翻转后页面数据的丢失: 异步调用导致的内存泄露: 类膨胀提

  • Android自定义开关按钮源码解析

    本文实例为大家分享了Android自定义开关的具体代码,供大家参考,具体内容如下 以 ToggleColorY 为例分析, ToggleImageY逻辑代码差不多 初始化参数 获取背景颜色,按钮颜色,开关状态 @SuppressLint("ResourceAsColor") private void initParame(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { TypedArray typed

  • Android自定义View多种效果解析

    最近项目里涉及到自定义View的东西还是挺多的,所以打算在自定义View上多花点时间,也顺便分享给大家. 先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 [3.重写onMeasure] 4.重写onDraw 1.首先在我们的res/values/目录下建立一个attrs.xml文件,然后在里面声明我们我们需要的自定义属性 我们定义了矩形的颜色,矩形的高度,矩形的宽度3个属性,format是指该属性的取值类型: 一共有:string,col

  • Android自定义Dialog原理实例解析

    Android开发过程中,常常会遇到一些需求场景--在界面上弹出一个弹框,对用户进行提醒并让用户进行某些选择性的操作, 如退出登录时的弹窗,让用户选择"退出"还是"取消"等操作. Android系统提供了Dialog类,以及Dialog的子类,常见如AlertDialog来实现此类功能. 一般情况下,利用Android提供的Dialog及其子类能够满足多数此类需求,然而,其不足之处体现在: 1. 基于Android提供的Dialog及其子类样式单一,风格上与App本

  • Android RecyclerView网格布局示例解析

    一个简单的网格布局 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/ap

  • Android TextView显示Html类解析的网页和图片及自定义标签用法示例

    本文实例讲述了Android TextView显示Html类解析的网页和图片及自定义标签.分享给大家供大家参考,具体如下: Android系统显示HTML网页的最佳控件为WebView,有时候为了满足特定需求,需要在TextView中显示HTML网页.图片及解析自定义标签. 1.TextView显示Html类解析的网页 CharSequence richText = Html.fromHtml("<strong>萝卜白菜的博客</strong>--<a href='

  • Android Activity共享元素动画示例解析

    目录 正文 TransitionManager介绍 Scene(场景) 生成场景 Transition(过渡) OverlayView和ViewGroupOverlay GhostView Activity的共享元素源码分析 我们先以ActivityA打开ActivityB为例 ActivityB返回ActivityA SharedElementCallback回调总结 正文 所谓Activity共享元素动画,就是从ActivityA跳转到ActivityB 通过控制某些元素(View)从Act

  • Android面向单Activity开发示例解析

    目录 正文 总结 正文 记得前一两年很多人都跟风面向单Activity开发,顾名思义,就是整个项目只有一个Activity.一个Activity里面装着N多个Fragment,再给Fragment加上转场动画,效果和多Activity跳转无异.其实想想还比较酷,以前还需要关注多个Acitivity之间的生命周期,现在只需关注一个,但还是需要对Fragment的生命周期进行关注. 其实早在六七年前GitHub上就有单Activity的开源库Fragmentation,后来谷歌也出了一个库Navig

  • Android Jetpack 组件LiveData源码解析

    目录 前言 基本使用 疑问 源码分析 Observer ObserverWrapper LifecycleBoundObserver MutableLiveData postValue setValue 问题答疑 LiveData 特性引出的问题 问题解决 最后 前言 本文来分析下 LiveData 的源码,以及其在实际开发中的一些问题. 基本使用 一般来说 LiveData 都会配合 ViewModel 使用,篇幅原因关于 ViewModel 的内容将在后续博客中分析,目前可以将 ViewMo

  • Android自定义View过程解析

    Android自定义的view,主要是继承view,然后实现ondraw这个方法,来进行绘制. 1. 编写自己的自定义view 2. 加入逻辑线程 3. 提取和封装自定义view 4. 利用xml中定义样式来影响显示效果 一.编写自定义的view 1.在xml中使用自己的view <!-- 可以使用view的公共属性,例如背景 --> <com.niuli.view.MyView android:layout_width="match_parent" android:

  • Android自定义滑动验证条的示例代码

    本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下: *注:不知道为什么,h5的标签在这里没用了,所以我也只能用Markdown的语法来写了 项目地址:https://github.com/994866755/handsomeYe.seekbar.github.io 需求: 在我们的某些应用中需要滑动验证.比如说这个样子的: 刚开始我也很懵逼要怎么去弄,结果我去看了一些人的代码,有人是用自定义viewgroup去做,就是viewgroup包含滑动块和滑动条.但我觉得太麻烦,

随机推荐