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,就是黏性数据,立马分发

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

相关推荐
百锦再2 小时前
Android Studio开发中Application和Activity生命周期详解
android·java·ide·app·gradle·android studio·studio
Kapaseker3 小时前
你可能不知道的Kotlin Data Class陷阱
kotlin
移动开发者1号3 小时前
Android现代进度条替代方案
android·app
万户猴3 小时前
【Android蓝牙开发实战-11】蓝牙BLE多连接机制全解析1
android·蓝牙
RichardLai883 小时前
[Flutter 基础] - Flutter基础组件 - Icon
android·flutter
清霜之辰3 小时前
安卓 Compose 相对传统 View 的优势
android·内存·性能·compose
_祝你今天愉快3 小时前
再看!NDK交叉编译动态库并在Android中调用
android
一杯凉白开4 小时前
Android View 事件的分发机制 四句口诀 先问拦截再派送,子不处理父兜底, 一旦消费无后续, 滑动冲突靠逻辑。
android
冬田里的一把火34 小时前
[Android]导航栏中插入电源菜单
android