Android LiveData源码分析:为什么他刷新数据比Handler好,能更节省资源,解决内存泄漏的隐患;

目录

  1. 为什么使用
  2. 是什么
  3. 使用+源码分析

一、为什么使用?

1.1 生命周期感知(避免无效刷新)

Handler 的问题​

假设用 Handler 定时刷新 UI:

java 复制代码
// 在 Activity 中
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        updateUI(); // 更新 UI
        handler.postDelayed(this, 1000); // 每秒刷新一次
    }
}, 1000);

如果用户退出 Activity 时忘记调用 handler.removeCallbacks(),​​后台线程会持续触发 UI 更新​​,导致资源浪费甚至崩溃。

​LiveData 的优化​

LiveData 会感知 Activity/Fragment 的生命周期:

typescript 复制代码
// ViewModel 中
MutableLiveData<String> data = new MutableLiveData<>();

// Activity 中观察数据
data.observe(this, new Observer<String>() {
    @Override
    public void onChanged(String value) {
        updateUI(value); // 只在界面活跃时触发
    }
});
1.2、自动解绑观察者(解决内存泄漏)

​Handler 的内存泄漏风险​

如果 Handler 持有 Activity 的隐式引用:

java 复制代码
// 匿名内部类 Handler 默认持有外部类 Activity 的引用
Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // 如果 Activity 销毁后收到消息,会导致内存泄漏
    }
};

即使 Activity 销毁,只要 Handler 的消息队列未清空,Activity 就无法被回收。

​LiveData 的自动解绑​

LiveData 通过 LifecycleOwner(如 Activity)绑定观察者:

kotlin 复制代码
data.observe(this, observer); // this 是 LifecycleOwner

当 Activity 销毁时,LiveData ​​自动移除观察者​​,断开与 Activity 的引用链,从根源避免内存泄漏。


二、是什么?

LiveData 是 Android Jetpack 组件中的一种 生命周期感知型数据持有类,专为 Android 设计,用于在 数据变化时 自动通知 处于活跃生命周期状态 的观察者(如 Activity/Fragment)。其核心作用是 解决数据与 UI 的实时同步问题,同时避免内存泄漏和生命周期导致的崩溃

LiveData和lifecycler(状态机)挂钩,这也是为什么他能感知生命周期。

LiveData他既是观察者又是被观察者。

三、使用+源码分析

3.1. 创建 LiveData 对象

kotlin 复制代码
class MyViewModel : ViewModel() {
    // MutableLiveData:可变的 LiveData(用于更新数据)
    private val _counter = MutableLiveData<Int>(0)
    // 对外暴露不可变的 LiveData(防止外部直接修改)
    val counter: LiveData<Int> get() = _counter

    fun increment() {
        _counter.value = (_counter.value ?: 0) + 1
    }
}

3.2. 在 Activity/Fragment 中观察数据

kotlin 复制代码
class MyActivity : AppCompatActivity() {
    private lateinit var viewModel: MyViewModel

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

        // 获取 ViewModel
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

        // 观察 LiveData 数据变化
        viewModel.counter.observe(this) { value ->
            // 当 counter 数据变化时,自动触发这里的代码
            textView.text = "计数:$value"
        }

        // 触发数据更新
        button.setOnClickListener {
            viewModel.increment()
        }
    }
}

3.2 我们从observe方法开始看,他是如何解决处理生命周期的问题,以及为什么刷新数据比handler好

java 复制代码
@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);
}

一进来,我们就可以看到,如果是销毁状态,直接就返回了。啥活都不执行了。减少资源消耗。

我们看看 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);observer被传递进去了,我们看看什么时候会回调。

java 复制代码
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
    // 1. 获取当前 LifecycleOwner(如 Activity/Fragment)的状态
    Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
    
    // 2. 如果当前状态是 DESTROYED(已销毁),自动移除观察者,避免内存泄漏
    if (currentState == DESTROYED) {
        removeObserver(mObserver); // 关键:自动解绑
        return;
    }

    // 3. 处理生命周期变化时的状态同步
    Lifecycle.State prevState = null;
    while (prevState != currentState) {
        prevState = currentState;
        boolean shouldBeActive = shouldBeActive();
        activeStateChanged(shouldBeActive);
        currentState = mOwner.getLifecycle().getCurrentState();
    }
}

这个方法是生命周期方法,生命周期状态变化自动触发逻辑。

我们会发现DESTROYED是Lifecycle下面的,这也是为什么livedata能监听生命周期的原因。

3.3 当我们调用修改数据的时候,他是如何分发过去的?

有两种

ini 复制代码
 _counter.value = (_counter.value ?: 0) + 1
_counter.postValue(1)

(1)我们看看第一种:text

java 复制代码
public class MutableLiveData<T> extends LiveData<T> {

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
        super();
    }

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

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
typescript 复制代码
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

传递的是null

Java 复制代码
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;
}

走下面的for循环逻辑,给所有的观察者分发数据。

java 复制代码
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;
    observer.mObserver.onChanged((T) mData);
}

直接进行分发 observer.mObserver.onChanged((T) mData);

kotlin 复制代码
fun interface Observer<T> {

    /**
     * Called when the data is changed is changed to [value].
     */
    fun onChanged(value: T)
}

(2)我们看看第二种:postValue postvalue,是子线程来发送数据,但是为什么主线程可以收到消息呢,还可以进行UI操作

ini 复制代码
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

这个一定会 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);通过handler切换到主线程。我们先看看这个runnable,里面修改了数据

java 复制代码
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};
java 复制代码
@Override
public void postToMainThread(@NonNull Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
                mMainHandler = createAsync(Looper.getMainLooper());
            }
        }
    }
    //noinspection ConstantConditions
    mMainHandler.post(runnable);
}

3.4 数据黏性是什么?

LiveData 的 数据黏性 指当新观察者注册时,自动收到最后一次设置的数据

比如:

java 复制代码
liveData.value = "A"
liveData.observe(owner) { value -> 
    println(value) // 立即打印 "A"
}

也就是在注册观察者之前,发送了数据,但还是能收到。

LiveData 内部通过 mData 字段存储当前数据,并通过 mVersion 记录数据版本号。

当调用 observe() 注册观察者时,LiveData 会立即检查是否需要分发当前数据:

不为null,就是黏性数据,立马分发

分发前会检测版本号,如果已经处理过了,就不用处理了。

相关推荐
还鮟8 分钟前
CTF Web的数组巧用
android
小蜜蜂嗡嗡1 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi002 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil3 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你3 小时前
Android View的绘制原理详解
android
移动开发者1号6 小时前
使用 Android App Bundle 极致压缩应用体积
android·kotlin
移动开发者1号6 小时前
构建高可用线上性能监控体系:从原理到实战
android·kotlin
ii_best11 小时前
按键精灵支持安卓14、15系统,兼容64位环境开发辅助工具
android
美狐美颜sdk11 小时前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭16 小时前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin