Jetpack之livedata原理

这篇具有很好参考价值的文章主要介绍了Jetpack之livedata原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.LiveData是什么?

Jetpack之livedata原理
只有在生命周期处于started和resumed时。livedata才会更新观察者
Jetpack之livedata原理

2.Livedata的各种使用方式

1.更新数据

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView : TextView = findViewById(R.id.tv_textview)

        // 1 观察者 眼睛 环节
        MyLiveData.info1.observe(this, {
            textView.text = it // 更新UI
        })

        // 完整写法 new  Observer  onChanged
        MyLiveData.info1.observe(this, object: Observer<String> {
            override fun onChanged(t: String?) {
                textView.text = t // 更新UI
            }
        })

        // 完整写法 new  Observer  onChanged
        MyLiveData.info1.observe(this, object: Observer<String> {
            override fun onChanged(t: String?) {
                textView.text = t // 更新UI
            }
        })


        // 完整写法 new  Observer  onChanged
        MyLiveData.info1.observe(this, object: Observer<String> {
            override fun onChanged(t: String?) {
                textView.text = t // 更新UI
            }
        })


        // 完整写法 new  Observer  onChanged
        MyLiveData.info1.observe(this, object: Observer<String> {
            override fun onChanged(t: String?) {
                textView.text = t // 更新UI
            }
        })




        // 2 触发数据改变 环节
        MyLiveData.info1.value = "default" // setValue 主线程

        thread {
            Thread.sleep(3000)
            MyLiveData.info1.postValue("三秒钟后,修改了哦")  // postValue 子线程
        }

        thread { // 子线程
            Thread.sleep(6000)
            MyLiveData.info1.postValue("六秒钟后,修改了哦")  // postValue 子线程
        }
    }

}
object MyLiveData { // 单例

    // 懒加载
    val info1: MutableLiveData<String> by lazy { MutableLiveData() }

}

2.模拟后台推送

class MainActivity2 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        // 启动服务
        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            startService(Intent(this, MyService::class.java))
            Toast.makeText(MainActivity2@this, "推送服务器启动成功", Toast.LENGTH_SHORT).show()
        }

        // 一股脑执行,他不会去检测生命周期
        // snedMessage(handler)


        // 眼睛 观察者  微信列表可见的情况下,才能做事情
        MyLiveData.data1.observe(this, {
            Log.d("server", "界面可见,说明用户在查看微信列表界面啦,更新消息列表UI界面:${it}")
            Toast.makeText(this, "更新消息列表UI界面成功:${it}", Toast.LENGTH_SHORT).show()
        })
    }
}
object MyLiveData { // 单例

    // 这里为info1的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    val data1 : MutableLiveData<String> by lazy { MutableLiveData() }

    init {
        // data1.value = "default" // 违背在 子线程 setValue
        data1.postValue("DDD") // 子线程 执行 postValue 非常OK
    }
}
// 模拟后台推送
class MyService : Service() {

    override fun onBind(intent: Intent): IBinder ? = null

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        thread {
            for (x in 1..100000) {
                Log.d("server", "服务器给推你推送消息啦(叮咚声响),消息内容是:${x}")
                MyLiveData.data1.postValue("服务器给推你推送消息啦,消息内容是:${x}")
                Thread.sleep(2000) // 5秒钟推一次
            }
        }
        return super.onStartCommand(intent, flags, startId)
    }
}

3.数据粘性

class MainActivity3 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)


        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            // version++  == 0   第一步
            MyLiveData.value1.value = "我就是我,不一样的烟火1" // 以前的旧数据
            MyLiveData.value1.value = "我就是我,不一样的烟火2" // 以前的旧数据
            MyLiveData.value1.value = "我就是我,不一样的烟火3" // 以前的旧数据
            MyLiveData.value1.value = "我就是我,不一样的烟火4" // 以前的旧数据
            MyLiveData.value1.value = "我就是我,不一样的烟火5" // 以前的旧数据

            startActivity(Intent(this, MainActivity4::class.java))
        }
    }
}
// this@MainActivity4 每个类都有符号
class MainActivity4 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main4)

        // 我后观察数据,居然能够收到 前面修改的数据,这就是 数据黏性
        /*MyLiveData.value1.observe(this, {
            Toast.makeText(this, "观察者数据变化:$it", Toast.LENGTH_SHORT).show()
        })*/

        // 第二步
        MyLiveData.value1.observe(this, object: Observer<String>{
            override fun onChanged(t: String?) {
                Toast.makeText(this@MainActivity4, "观察者数据变化$t", Toast.LENGTH_SHORT).show()
            }
        })

        /*// 此观察者 和 handler没有区别,一股脑的执行 (极端的情况,可以用)
        // 手动考虑释放工作
        MyLiveData.value1.observeForever({

        })

        //  // 关心的新数据
        MyLiveData.value1.postValue("1111")

        //  // 关心的新数据
        MyLiveData.value1.postValue("1111")


        //  // 关心的新数据
        MyLiveData.value1.postValue("1111")

        //  // 关心的新数据
        MyLiveData.value1.postValue("1111")


        // 先订阅
        ok(object : Callback {
            override fun show() {
            }
        })*/
    }

    fun ok(callback: Callback) {
        // 后触发
        callback.show()
    }

    override fun onStart() {
        super.onStart()
    }


    override fun onDestroy() {
        super.onDestroy()
        // 手动释放
        // MyLiveData.value1.removeObserver()
    }
}
object MyLiveData {

    // 这里为info1的MutableLiveData 懒加载初始化(懒加载:用到时才加载)
    val value1 : MutableLiveData<String> by lazy { MutableLiveData() }

}

3.Livedata源码解析

Jetpack之livedata原理
下面来看observe方法做了哪些操作,observe方法的主要代码如下:

    /**
     * Adds the given observer to the observers list within the lifespan of the given
     * owner. The events are dispatched on the main thread. If LiveData already has data
     * set, it will be delivered to the observer.
     * <p>
     * The observer will only receive events if the owner is in {@link Lifecycle.State#STARTED}
     * or {@link Lifecycle.State#RESUMED} state (active).
     * <p>
     * If the owner moves to the {@link Lifecycle.State#DESTROYED} state, the observer will
     * automatically be removed.
     * <p>
     * When data changes while the {@code owner} is not active, it will not receive any updates.
     * If it becomes active again, it will receive the last available data automatically.
     * <p>
     * LiveData keeps a strong reference to the observer and the owner as long as the
     * given LifecycleOwner is not destroyed. When it is destroyed, LiveData removes references to
     * the observer &amp; the owner.
     * <p>
     * If the given owner is already in {@link Lifecycle.State#DESTROYED} state, LiveData
     * ignores the call.
     * <p>
     * If the given owner, observer tuple is already in the list, the call is ignored.
     * If the observer is already in the list with another owner, LiveData throws an
     * {@link IllegalArgumentException}.
     *
     * @param owner    The LifecycleOwner which controls the observer
     * @param observer The observer that will receive the events
     */
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        owner.getLifecycle().addObserver(wrapper);
    }

observe方法首先会通过assertMainThread方法检查程序当前是否运行在主线程中,如果不是,则抛出一个异常。使用时需要确保observe方法是执行在主线程中的,且LiveData和生命周期相关联,如果当前状态是非活跃状态则不会执行。这里提一下,如果想让数据监测变化不受活动状态的影响,可以使用observeForever方法,这样Activity即使不处于活动状态,也可以接收到改变的数据,但当Activity销毁时,一定要主动调用removeObserver方法,否则LiveData会一直存在,这会导致内存泄漏。
activity中的addObserver传进来的只是一个接口,在这个接口上进行进一步封装为
LifecycleBoundObserver,保存了宿主的lifecycleowner;shouldBeActive() 是为了判断宿主是否为活跃状态。

/**
 * A simple callback that can receive from {@link LiveData}.
 *
 * @param <T> The type of the parameter
 *
 * @see LiveData LiveData - for a usage description.
 */
public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(T t);
}
    class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

LifecycleBoundObserver实现了LifecycleEventObserver接口,当页面发生改变的时候,程序会走到onStateChanged方法中。从上述源码可以看出,当页面被销毁时会调用removeObserver移除观察,所以使用LiveData的observe方法不用担心存在内存泄漏的风险。如果之前的周期与当前不同,则会同步一次状态,并调用activeStateChanged方法,而activeStateChanged方法则会调用dispatchingValue方法分发数据。dispatchingValue方法的代码如下:

    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

这里通过使用mDispatchingValue变量标记来防止分发相同的内容,通过循环方式遍历所有的观察者,通过considerNotify方法更新数据。为的是时时刻刻读取lifecycle生命周期,获取到最新的生命周期状态:

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //这里就是粘性的原因,如果不想粘性改成等于号即可
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

如果观察者已经不属于活动状态,则直接返回,并通过比较数据的版本号判断数据是否需要更新。如果需要更新则会回调到observer的onChanged方法中,从而实现在UI层接收数据的回调。那么这个版本号什么时候会更新呢?来看设置数据的方法,这里以setValue方法为例,代码如下:

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

可以看到,当调用setValue方法时,数据版本号会改变,并且会通过dispatching-Value方法进行数据处理,这样就实现了LiveData可观察的特性。

对于postvalue而言:

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

利用handler将线程切换到主线程

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
    @Override
    public void postToMainThread(Runnable runnable) {
        mDelegate.postToMainThread(runnable);
    }

Jetpack之livedata原理
Jetpack之livedata原理
Jetpack之livedata原理

接下来我们看runnable的代码,本质上也是调用Setvalue:文章来源地址https://www.toymoban.com/news/detail-437755.html

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

到了这里,关于Jetpack之livedata原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android JetPack~LiveData(二) 数据倒灌问题

    Android数据绑定技术一,企业级开发 Android数据绑定技术二,企业级开发 Android  JetPack~ DataBinding(数据绑定)(一)    集成与使用 Android  JetPack~ LiveData (一)   介绍与使用 Android JetPack~LiveData(二) 数据倒灌问题 Android  JetPack~ ViewModel (一)   介绍与使用 如果我们在一个home页面获取网络

    2024年02月02日
    浏览(29)
  • Android-Jetpack>;>; LiveData粘性数据

    米哈游校招技术提前批来啦 靠谱内推,全程跟进! 有需要的小伙伴可以帮忙辅导简历哈! 投递后可私信我跟进~ 内推码:NE449    入职 南大通用 个人感受 Hello啊各位朋友们,这里先说一下个人情况吧,我是河北工业大学23届的本科生,计算机本专业的。然后我是春招进的南

    2024年02月17日
    浏览(29)
  • Jetpack业务架构—四件套(Lifecycle、ViewModel、LiveData、DataBinding)

    Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法、减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者可将精力集中于真正重要的编码工作。 Android Jetpack组件的优势: Jetpack推出的主要目的是为了能够让开发者更加快速、方便以及高质

    2024年02月09日
    浏览(29)
  • 【Jetpack】ViewModel + LiveData + DataBinding 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )

    ViewModel 架构组件 是 视图 View 与 数据模型 Model 之间 数据交互的 桥梁 ; 传统 Android 开发中 , 视图 View 与 数据模型 Model 都在 Activity 中维护 , 导致 二者有很高的耦合度 , 不利于代码维护 ; 引入了 ViewModel 架构组件后 , 视图 View 与 数据模型 Model 之间实现了解耦 , 同时也能 保证二

    2024年02月01日
    浏览(35)
  • 【Jetpack】Room + ViewModel + LiveData 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )

    在上一篇博客 【Jetpack】使用 Room 框架访问 Android 平台 SQLite 数据库 ( 导入依赖 | 定义 Entity 实体类 | 定义 Dao 数据库访问对象接口 | 定义数据库实例类 ) 中 , 实现了 使用 Room 框架访问 Android 中的 SQLite 数据库的操作 , 每当数据库中的数据发生变化时 , 就需要开启线程 , 重新获

    2024年02月06日
    浏览(30)
  • Android资深工程书之LiveData核心组件原理剖析

    LiveData是Android架构组件库中的一个类,用于在应用程序组件之间共享数据。它是一种可观察的数据持有者,可以感知应用程序组件的生命周期,并在数据发生变化时通知观察者。 在Android应用程序中使用LiveData,你可以按照以下步骤进行: 创建LiveData实例: 在ViewModel类中创建

    2024年02月12日
    浏览(28)
  • Transform LiveData

    查询资料的其中一个场景: 创建一个回调函数,当查询后台的时候,后台有结果了,回调对应的回调函数,并将结果保存到LiveData中。 如果 RepoViewModel的部分写成这样: 这种写法有如下两个问题: 1.当输入新的的时候,DataModel会返回新的LiveData,这样View每次都要去ob

    2024年02月16日
    浏览(24)
  • LiveData简单使用

    1.LiveData是基于观察者模式,可以用于处理消息的订阅分发的组件。  LiveData组件有以下特性:     1) 可以感知Activity、Fragment生命周期变化,因为他把自己注册成LifecycleObserver。     2) LiveData可以注册多个观察者,只有数据有变化,观察者就可以收到更新的数据,          但

    2024年02月07日
    浏览(23)
  • Android架构组件LiveData

    LiveData LiveData是基于观察者模式创建的,其中,LiveData是被观察者,观察者通过注册方法,监听被观察者的数据变化。LiveData在数据发生变化的时候,会通知观察者。 LiveData是一个容器,存放数据的容器,它的数据变化可以被监听,也就是LiveData是一个被观察者,如下,创建了一

    2024年02月13日
    浏览(24)
  • LiveData和ViewModel源码学习

    LiveData ObserverWrapper 数据观察者 LifecycleEventObserver 生命周期观察者 活跃状态接受并更新数据 刷新页面数据 非活跃状态暂停接收数据 防止崩溃, 销毁状态的时候移除观察者 防止内存泄漏 数据可以监听 数据倒灌,就是先发送数据,通过生命周期响应来触发change 数据粘性,先发

    2024年04月12日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包