Android 面试总结 - LiveData,架构师必备技能

// 很关键的 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.

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

if (!observer.shouldBeActive()) {

// 更改 ObserverWrapper 的 mActive 为 false 非活跃状态

observer.activeStateChanged(false);

return;

}

// 版本号来了~~!

if (observer.mLastVersion >= mVersion) {

return;

}

// 同步版本号,

observer.mLastVersion = mVersion;

// 这里终于调用了我们 LiveData.observe 方法传入的 Observer 对象的 onChanged 方法。

// 终于形成了闭环

observer.mObserver.onChanged((T) mData);

}

来看看版本号 LiveData#mVersion

static final int START_VERSION = -1;

private int mVersion;

// 当创建 LiveData 时传入了初始值,则 mVersion 的版本为 -1 + 1 也就是 0

public LiveData(T value) {

mData = value;

mVersion = START_VERSION + 1;

}

// 大多数我们会使用无参构造,这时候 mVersion 是 START_VERSION -1

/**

  • Creates a LiveData with no value assigned to it.

*/

public LiveData() {

mData = NOT_SET;

mVersion = START_VERSION;

}

那 mVersion 的值是什么时候更改的呢?

其实在刚刚分析 setValue 时就 ++ 了,回顾一下

protected void setValue(T value) {

assertMainThread(“setValue”);

mVersion++;

mData = value;

dispatchingValue(null);

}

而且我们也知道 postValue 最后会调用 setValue,所以 mVersion 值更改的只是就到这儿了。 这时候是不是可以分析一下第三个问题

3. 设置相同的值,订阅的观察者们会收到同样的值吗 在分发值的过程中没有判断过新值是否等于老值的代码出现,只出现了一个判断 version,通过 demo 尝试也会发现,会收到同样的值的哟。

以下资料全部免费赠送,需要的可以点击这里:https://github.com/hunanmaniu/AndroidNotes

架构师筑基必备技能


目前Android APP开发主流语言就是Java语言,Java语言最大的特性就是提高了软件的交互可能性,可以说安卓手机几乎所有应用程序都是利用Java语言来进行编写的。

JAVA知识要点:

1、 Java序列化、泛型与反射

2、虚拟机底层原理

3、Android内存原理

4、 Java高级并发原理详解

5、 编译时技术掌握与实战

6、JDK高级动态代理

7、高级数据结构与算法

8、 Java IO操作

9、

。。。。

Android R FrameWork源码与UI


在Android中,Framework泛指系统架构层。Framework的中文意思是“框架”,在软件开发中通常指开发框架,在一个系统中处于内核层之上,为顶层应用提供接口,被设计用来帮助开发者快速开发顶层应用,而不必关心系统内核运行机制,通常Framework都会隐藏main函数等应用程序必须的组件,开发人员只需把精力放在功能代码的实现上。说简单点,Framework具体的工作也就是为android应用开发的开发人员提供了一系列的服务和API的接口。

UI其实并不是单纯指用户看到的效果。因为在Android开发中,每个控件背后都有一套深层次的体系在支撑,自然而然,会UI不单纯指的是会自定义控件,我们还应该知道自定义控件背后的执行流程,包括从Activity的创建,XML的解析,到每个控件的测量、布局、绘制。当然在中间还夹杂着比如动画、事件分发机制、嵌套滑动机制等知识点。还有谷歌提供的一些UI框架也使我们要掌握的对象,比如Jetpack组件库、Material Design等。

知识要点:

1、 FrameWork源码解析(SDK 30)

2、Android常用组件深入解析

3、JetPack全家桶

4、Android R新特性解析

。。。。。

大厂内部APP调优方案


性能优化是一个项目必须要经历的过程,你的应用好与坏都是在用户使用的过程中反映出来的,如果性能优化没有做好,对于你的应用来说影响是非常大的。尤其是现在的Android市场竞争非常激烈,如果你的应用体验没有竞品的好,那么用户流失是必然的。

性能优化不是一件简单的事情,每个应用的性能好与坏无法由一个人来决定,因为性能优化的维度有太多了,从我们项目的整体架构,到我们代码的每一个细节,再到应用使用环境的测试,只有步步为营,才能做好一个项目的优化。大部分开发者把性能优化指向与不闪退就行,但是实际上性能优化包含了很多方面,比如从简单的启动优化、 UI优化、 卡顿优化、 崩溃优化、 安全性优化,到深层次的弱网优化、 大图加载优化、 储存优化、 高效传输优化、 极限瘦身优化,再到实际开发过程中的OOM问题原理解析、 ANR问题解析、 Crash监控方案。要想把这些优化流程做好,我们不仅从项目架构、代码规范等方面入手,还用学会利用第三方的检测工具来检测项目性能,最主要是,我们需要一套完整的性能优化方案,这正是我们所缺少的,所以我们必须要把缺少的补上, 打造一套真正的完整的性能优化体系,把性能优化流程化,常态化。

1、 APP基础优化

2、APP深度优化

3、开发焦点问题优化

4、编程效率优化

5、项目实战

抖音在APK包大小资源优化的实践

优酷响应式布局技术全解析

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

文末

不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊~

小编将自己6年以来的面试经验和学习笔记都整理成了一个**937页的PDF,**以及我学习进阶过程中看过的一些优质视频教程。**上传在我的GitHub中:Android架构视频+BATJ面试专题PDF+学习笔记**请君自取,无偿分享!

0504700954)]
[外链图片转存中…(img-m1YOx5W6-1710504700954)]
[外链图片转存中…(img-DgoxcS2W-1710504700955)]
[外链图片转存中…(img-luDr9EH5-1710504700955)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-BSHS96Vu-1710504700956)]

文末

不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊~

小编将自己6年以来的面试经验和学习笔记都整理成了一个**937页的PDF,**以及我学习进阶过程中看过的一些优质视频教程。**上传在我的GitHub中:Android架构视频+BATJ面试专题PDF+学习笔记**请君自取,无偿分享!

[外链图片转存中…(img-Shm5njAZ-1710504700956)]

其实看到身边很多朋友抱怨自己的工资很低,包括笔者也是一样的,其原因是在面试过程中没有给面试官一个很好的答案。所以笔者会持续更新面试过程中遇到的问题,也希望大家和笔者一起进步,一起学习。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值