Jetpack之livedata原理分析

文章详细介绍了Android开发中的LiveData组件,包括其作为观察者模式在主线程中更新UI的机制,如何在生命周期内有效管理数据变化,以及数据粘性特性,使得新活动能够接收到之前的数据。同时,通过示例展示了后台服务如何模拟推送更新。
摘要由CSDN通过智能技术生成

1.LiveData是什么?

在这里插入图片描述
只有在生命周期处于started和resumed时。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源码解析

在这里插入图片描述
下面来看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);
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

接下来我们看runnable的代码,本质上也是调用Setvalue:

    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);
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gujunhe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值