Android 面试总结 - LiveData

本文详细解析了在Android应用中,如何使用Kotlin的ViewModel和LiveData,特别是观察者模式的实现机制,包括观察者如何感知Activity的生命周期,以及setValue和postValue的区别。
摘要由CSDN通过智能技术生成

class MainActivity : AppCompatActivity() {

// 创建 ViewModel 方式 1

// 通过 kotlin 委托特性创建 ViewModel

// 需添加依赖 implementation ‘androidx.activity:activity-ktx:1.2.3’

// viewModels() 内部也是通过 创建 ViewModel 方式 2 来创建的 ViewModel

private val mainViewModel: MainViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate (savedInstanceState)

setContentView(R.layout.activity_main)

// 创建 ViewModel 方式 2

val mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)

// 通过 LiveData.observe 订阅观察者

mainViewModel.nameListResult.observe(this, {

Log.i(“MainActivity”, “mainViewModel: nameListResult: $it”)

})

mainViewModel.getNames()

}

}

打开app -> 正常看到日志

18:03:02.575 : mainViewModel: nameListResult: [张三, 李四]

源码解析

====

LiveData 通过 observe 方法来订阅观察者,以此为查看源码的入口:

方法注释包含的知识很多,请认真阅读注释 (百度翻译过来的)。

private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =

new SafeIterableMap<>();

/**

  • 1、在给定 owner 的生命周期内,将给定的观察者添加到观察者列表中。

  • 2、事件在主线程上调度。

  • 3、如果LiveData已经有数据集,它将被交付给观察者。

  • 4、仅当所有者处于{@link Lifecycle.State#STARTED}或{@link Lifecycle.State#RESUME}状态

*(活动)时,观察者才会接收事件。

  • 5、如果所有者移动到{@link Lifecycle.State#DETROYED}状态,观察者将自动被删除。

  • 6、当数据在{@code owner}未激活时发生更改时,它将不会收到任何更新。

  • 7、如果它再次激活,它将自动接收最后可用的数据。

  • 8、只要给定的LifecycleOwner未被销毁,LiveData就会保留对观察者和所有者的强引用。

  • 9、销毁后,LiveData将删除对所有者的引用。

  • 10、如果给定的所有者已经处于{@link Lifecycle.State#DESTROYED}状态,LiveData将忽略该调用。

  • 11、如果给定的所有者、观察者元组已经在列表中,则忽略该调用。

  • 12、如果观察者已经列表中,LiveData将抛出@link IllegalArgumentException}。

  • @param owner 控制观察者的生命周期所有者

  • @param observer 将接收事件的观察者

*/

@MainThread

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

assertMainThread(“observe”);

if (owner.getLifecycle().getCurrentState() == DESTROYED) {

// ignore

// owner 的状态是 DESTROYED 则不往下走。对应方法注释的第 10 点。

return;

}

// 创建 owner 和 observer 的包装对象 LifecycleBoundObserver

LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

// observer 对象作为 Key,包装对象 wrapper 作为 value,存进 Map 结构对象 mObservers

// putIfAbsent 方法:若 Map 里有这个key,则返回对应的 Value 值。

// 仅当 key 不存在时才会将 key value 存进 Map

// put 进去的是 LifecycleBoundObserver 类型对象,返回的是 ObserverWrapper 对象,

// 不难猜出 LifecycleBoundObserver 是 ObserverWrapper 的子类或者实现类

ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

// 若 existing 不为null, 并且 existing 中的 owner 对象和 observe 方法传入的对象不是同一个对象,

// 则抛出异常,不可以添加同一个 Observer 到两个不同的生命周期对象。对应方法注释的第 12 点。

if (existing != null && !existing.isAttachedTo(owner)) {

throw new IllegalArgumentException(“Cannot add the same observer”

  • " with different lifecycles");

}

if (existing != null) {

// 若 existing 不为 null,则忽略该调用。对应方法注释的第 12 点。

return;

}

// 将 owner 和 observer 的包装对象添加到 owner.getLifecycle()。对应方法注释的第 1 点。

owner.getLifecycle().addObserver(wrapper);

}

第一个问题中 LiveData 怎么感知生命周期感知?

我们可以回答了,调用 observe 方法时,会调用 owner.getLifecycle().addObserver 已达到感知生命周期的目的。 observe 方法的内容很少,接着看下 owner 和 observer 的包装对象 LifecycleBoundObserver

LiveData 的内部类

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

@NonNull

final LifecycleOwner mOwner;

// 构造函数 owner 赋值给属性 mOwner, observer 则调用了 super

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

super(observer);

mOwner = owner;

}

@Override

boolean shouldBeActive() {

return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);

}

/**

  • 当 source (也就是 mOwner) 的生命周期改变时会回调此方法

*/

@Override

public void onStateChanged(@NonNull LifecycleOwner source,

@NonNull Lifecycle.Event event) {

// 获取当前 mOwner 的生命周期状态

Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();

if (currentState == DESTROYED) {

// 如果是已销毁状态,则调用 LiveData#removeObserver 方法进行移除 mObserver (mObserver 是 LifecycleBoundObserver 的父类 ObserverWrapper 的属性,通过 ObserverWrapper 的构造函数来赋值),对应 LiveData#observe 方法注释的第 12 点。

removeObserver(mObserver);

return;

}

Lifecycle.State prevState = null;

while (prevState != currentState) {

prevState = currentState;

activeStateChanged(shouldBeActive());

currentState = mOwner.getLifecycle().getCurrentState();

}

}

@Override

boolean isAttachedTo(LifecycleOwner owner) {

return mOwner == owner;

}

@Override

void detachObserver() {

// 从 mOwner 中移除此观察者

mOwner.getLifecycle().removeObserver(this);

}

}

onStateChanged 方法中注释如果是已销毁状态,则调用 LiveData#removeObserver 方法进行移除 mObserver (mObserver 是 LifecycleBoundObserver 的父类 ObserverWrapper 的属性,通过 ObserverWrapper 的构造函数来赋值),对应 LiveData#observe 方法注释的第 12 点。 同时第一个问题已经得到了解决: **LiveData 怎么感知生命周期感知?需要取消注册吗?**LiveData#observe 看完啦,该看 setValue 和 postValue 了。

/**

  • Sets the value. If there are active observers, the value will be dispatched to them.

  • 设置值。如果存在活动的观察者,则会将值分派给他们。

  • This method must be called from the main thread. If you need set a value from a background

  • thread, you can use {@link #postValue(Object)}

  • 必须从主线程调用此方法。如果需要从后台线程设置值,可以使用{@link#postValue(Object)}

  • @param value The new value

*/

@MainThread

protected void setValue(T value) {

// 检查当前线程是否是主线程,若非主线程则会抛异常

assertMainThread(“setValue”);

// 很关键的 mVersion ,在这里进行 + 1 操作

mVersion++;

// 将新值赋值给属性 mData

mData = value;

// 分发值 (后面再看它具体实现)

dispatchingValue(null);

}

关键哟:setValue 必须在主线程中调用

/**

  • Posts a task to a main thread to set the given value. So if you have a following code

  • executed in the main thread:

  • 将任务发布到主线程以设置给定值。因此,如果在主线程中执行以下代码:

  • liveData.postValue(“a”);

  • liveData.setValue(“b”);

  • The value “b” would be set at first and later the main thread would override it with

  • the value “a”.

  • 首先设置值“b”,然后主线程将用值“a”覆盖它。(等我们看完了 postValue 具体怎么做的,这个官方小示例就能明白了)

  • If you called this method multiple times before a main thread executed a posted task, only

  • the last value would be dispatched.

  • 如果在主线程执行已发布任务之前多次调用此方法,则只会调度最后一个值。

  • @param value The new value

*/

protected void postValue(T value) {

boolean postTask;

synchronized (mDataLock) {

postTask = mPendingData == NOT_SET;

// 新值赋值给属性 mPendingData

mPendingData = value;

}

// 当 mPendingData == NOT_SET 时,才会往下走

if (!postTask) {

return;

}

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

}

ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable); 看似是把 mPostValueRunnable 这 Runnable 对象发送到主线程?

private final Runnable mPostValueRunnable = new Runnable() {

@SuppressWarnings(“unchecked”)

@Override

public void run() {

Object newValue;

synchronized (mDataLock) {

// 将刚赋值新值的 mPendingData 赋值给对象 newValue

newValue = mPendingData;

// 将 mPendingData 重置为 NOT_SET

// 回头看看 postValue 会明白为啥要这么做

mPendingData = NOT_SET;

}

// 嘶 ~ 在这儿调用了 setValue,

setValue((T) newValue);

}

};

这时候看出来 postValue 最终还是调用了 setValue 再看下 postToMainThread

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)

public class ArchTaskExecutor extends TaskExecutor {

@NonNull

private TaskExecutor mDelegate;

private ArchTaskExecutor() {

mDefaultTaskExecutor = new DefaultTaskExecutor();

mDelegate = mDefaultTaskExecutor;

}

@Override

public void postToMainThread(Runnable runnable) {

mDelegate.postToMainThread(runnable);

}

}

由 DefaultTaskExecutor 对象调用的 postToMainThread

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)

public class DefaultTaskExecutor extends TaskExecutor {

@Nullable

private volatile Handler mMainHandler;

@Override

public void postToMainThread(Runnable runnable) {

if (mMainHandler == null) {

synchronized (mLock) {

if (mMainHandler == null) {

// MainLooper 主线程的 Looper 呢

mMainHandler = createAsync(Looper.getMainLooper());

}

}

}

//noinspection ConstantConditions

mMainHandler.post(runnable);

}

private static Handler createAsync(@NonNull Looper looper) {

if (Build.VERSION.SDK_INT >= 28) {

return Handler.createAsync(looper);

}

if (Build.VERSION.SDK_INT >= 16) {

try {

return Handler.class.getDeclaredConstructor(Looper.class, Handler.Callback.class,

boolean.class)

.newInstance(looper, null, true);

} catch (IllegalAccessException ignored) {

} catch (InstantiationException ignored) {

} catch (NoSuchMethodException ignored) {

} catch (InvocationTargetException e) {

return new Handler(looper);

}

}

return new Handler(looper);

}

}

最终是通过 Handler 的 post ~~ 太熟悉了。

看代码得知 Handler 的 Looper 是 MainLooper

So LiveData#postValue 最终使用主线程将新 value 分发给观察者。意味着我们可以在任何线程调用 postValue,而不用担心线程问题。因为 LiveData 内部做好了线程转换。

第二个问题:2. setValue 和 postValue 有什么区别

简单来说:setValue 只能在主线程使用,而 postValue 不限制线程。

由上知道了:setValue 调用了 dispatchingValue, postValue 调用了 setValue 所以最终也是调用 dispatchingValue

void dispatchingValue(@Nullable ObserverWrapper initiator) {

// mDispatchingValue 是一个标记,为 true 表示正在分发 value,

if (mDispatchingValue) {

mDispatchInvalidated = true;

return;

}

mDispatchingValue = true;

do {

mDispatchInvalidated = false;

if (initiator != null) {

// 1.

considerNotify(initiator);

initiator = null;

} else {

// 2.

for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =

mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {

considerNotify(iterator.next().getValue());

if (mDispatchInvalidated) {

break;

}

}

}

} while (mDispatchInvalidated);

mDispatchingValue = false;

}

从 setValue 中看到调用 dispatchingValue 时传入的参数是 null 所以我们先看注释第 2 点的情况,使用迭代器获取 ObserverWrapper 对象传到 considerNotify 方法。

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.

// 分发的时候判断当前观察者是否不活跃了

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

fy for a more predictable notification order.

// 分发的时候判断当前观察者是否不活跃了

最后

那我们该怎么做才能做到年薪60万+呢,对于程序员来说,只有不断学习,不断提升自己的实力。我之前有篇文章提到过,感兴趣的可以看看,到底要学习哪些知识才能达到年薪60万+。

通过职友集数据可以查看,以北京 Android 相关岗位为例,其中 【20k-30k】 薪酬的 Android 工程师,占到了整体从业者的 30.8%!

北京 Android 工程师「工资收入水平 」

[外链图片转存中…(img-1iFgsxAi-1714336516011)]

今天重点内容是怎么去学,怎么提高自己的技术。

1.合理安排时间

2.找对好的系统的学习资料

3.有老师带,可以随时解决问题

4.有明确的学习路线

当然图中有什么需要补充的或者是需要改善的,可以在评论区写下来,一起交流学习。

[外链图片转存中…(img-2MsuA5Hn-1714336516011)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值