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包大小资源优化的实践
优酷响应式布局技术全解析
网络优化
手机淘宝双十一性能优化项目揭秘
高德APP全链路源码依赖分析
彻底干掉OOM的实战经验分享
微信Android终端内存优化实践
对标腾讯T3.3架构师
Android框架体系架构(高级UI+FrameWork源码) 这块知识是现今使用者最多的,我们称之Android2013~2016年的技术。
Android开发者也往往因为网上Copy代码习惯了而导致对这块经常“使用”的代码熟悉而又陌生:熟悉的是几乎天天在和它们打交道, 天天在复制这些代码 ;陌生的是虽然天天和这些代码打交道,但是并没有深入研究过这些代码的原理,代码深处的内涵。
知识要点:
1、架构师设计思想篇
2、 手淘全套架构设计与实现
3、 开源框架
4、OKHttp网络框架
5、一线大厂核心框架剖析与实现
NDK模块开发(音视频系列)
NDK(Native Development Kit缩写)一种基于原生程序接口的软件开发工具包,可以让您在 Android 应用中利用 C 和 C++ 代码的工具。通过此工具开发的程序直接在本地运行,而不是虚拟机。
在Android中,NDK是一系列工具的集合,主要用于扩展Android SDK。NDK提供了一系列的工具可以帮助开发者快速的开发C或C++的动态库,并能自动将so和Java应用一起打包成apk。
知识要点:
1、NDK开发之C/C++入门
2、JNI模块开发
3、Linux编程
4、底层图片处理
5、音视频开发
6、机器学习
Flutter学习进阶
2021 年无疑是 Flutter 技术如火如荼发展的一年。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
总结
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
上述【高清技术脑图】以及【配套的架构技术PDF】可以关注我免费获取
[外链图片转存中…(img-GLBXHOXg-1711300877792)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-8OpSAz0o-1711300877792)]
总结
最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
[外链图片转存中…(img-wQuO5uLi-1711300877793)]
[外链图片转存中…(img-ItGyPmPz-1711300877793)]
上述【高清技术脑图】以及【配套的架构技术PDF】可以关注我免费获取
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。