Android 相关源码分析

@Nullable Executor callbackExecutor) {

DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);

return hasJava8Types

? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
singletonList(executorFactory);

}

Retrofit 默认有两个转换器,一个可以把响应转成 ResponseBody,一个可以把响应转成 Optional

converterFactories.add(new BuiltInConverters());

converterFactories.addAll(this.converterFactories);

converterFactories.addAll(platform.defaultConverterFactories());

List<? extends Converter.Factory> defaultConverterFactories() {

return hasJava8Types ? singletonList(OptionalConverterFactory.INSTANCE) : emptyList();

}

[](()Retrofit 分析

Retrofit 最大个贡献是改变了描述 API 的方式,尤其是描述 RESTful API 的方式,让客户端对 API 的调用更加的简单、直观、安全

Retrofit 这种 “ 接口 + 抽象方法 + 注解 ” 的方式虽然可以实现 API 的描述,但是不能可视化,不能结构化,不能文档化,不能直接 mock,不能自动化测试,不能指定公共参数。所以我觉得换成 “ 配置文件(JSON?) + GUI 插件 ” 等其它方式要更好一点

[](()ViewStub 29


只是一个占位,继承 View,不绘制(setWillNotDraw(true)),且宽高为 0(setMeasuredDimension(0, 0)),inflate() 就是从父容器中移除自己并 inflate 给定的 view 到自己的本来的位置(index 和 layoutParams),由于移除后就不知道自己的父容器了所以 inflate() 只能调用一次。ViewStub 的 setVisibility() 方法一般不建议使用,如果用,那么在没 inflate() 的情况下会自动调用 inflate()

[](()Handler 29


Looper.prepare(); 可以给一个普通线程关联一个消息队列,Looper.loop(); 开始循环处理消息队列中的消息,new 一个 Handler 可以发送和处理消息,创建 Handler 需要指定 Looper,如果不指定那么表明是针对当前线程的 Looper 的,主线程有个创建好的 Looper.getMainLooper() 单例可以直接用

Looper.loop(); 是个死循环,循环获取队列中的消息,转发给消息的 target 去处理,也就是当初发送它的 Handler 去处理

Handler 处理消息的线程就是它关联的 Looper 所在的线程,也就是说创建 Handler 时传的 Looper 在哪个线程调用了 Looper.loop();,那么就在哪个线程回调 handleMessage()

for (;😉 {

Message msg = queue.next(); // might block

msg.target.dispatchMessage(msg);

}

queue.next() 最终调用的是名为 nativePollOnce() 的 native 方法,而该方法使用的是 epoll_wait 系统调用,表示自己在等待 I/O 事件,线程可以让出 CPU,等到 I/O 事件来了才可以进入 CPU 执行

而每次有新消息来的时候 enqueueMessage(),最终都会调用名为 nativeWake() 的 native 方法,该方法会产生 I/O 事件唤醒等待的线程

所以 nativePollOnce() / nativeWake() 就像对象的 wait() / notify() 一样,死循环并不会一直占用 CPU,如果没有消息要处理,就让出 CPU 进入休眠,只有被唤醒的时候才会进入 CPU 处理工作

IdleHandler 可以在消息队列中的消息都处理完了,进入休眠之前做一些工作,所以可以利用 Looper.myQueue().addIdleHandler() 做一些延迟任务,如在主线程中延迟初始化一些大对象或做一些可能耗时的操作

Handler 的延迟发消息功能如 sendMessageDelayed()postDelayed() 是通过延迟唤醒实现的,在消息入队的时候就确定好消息要唤醒的时间,即 msg.when = SystemClock.uptimeMillis() + delayMillis,插入自己在队列中应该出现的位置,在取下一个消息时延迟 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE) 时间去取即可

线程池技术保持线程活跃也是通过 epoll 机制实现的,死循环中阻塞地从队列中取消息,利用 LockSupport.park()Conditionawait() 就能让线程保持活跃的同时让出 CPU 等待事件

[](()RecyclerView 1.1.0


[](()术语

目的: 在有限的窗口中显示大量的数据

Adapter: 为数据集中的数据项提供对应的 View

Position: 数据项在数据集中的位置

Index: View 在容器中的位置

Binding: 为 position 位置的数据准备对应 View 的过程

Recycle (view): 之前使用过的 View 可能会被放到缓存中,之后在显示相同类型数据时可以直接拿出来重用

Scrap (view): 进入临时 detached 状态的 View,不用完全 detached 就能重用

Dirty (view): 在被显示前必须重新绑定的 View

LayoutManager 维护的 LayoutPosition 理论上和 Adapter 维护的 AdapterPosition 是一样的,但是对数据集 position 的修改是马上就起效的,而修改布局的 position 需要一定时间。所以最好在写 LayoutManager 的时候用 LayoutPosition,写 Adapter 的时候用 AdapterPosition

如果数据集发生了变化,而你想通过 Diff 算法提升性能(只刷新必要的 View),那么可以直接使用 ListAdapter 这个 Adapter,它会在后台线程中比较新 List 和 旧 List 从而自动完成局部更新。或者在自己的 Adapter 中直接使用 AsyncListDiffer 实现。再或者直接使用 DiffUtil 工具比较列表也可以,更灵活,但也更繁琐

如果列表是有序的,那么使用 SortedList 可能比使用 List 要更好一些

[](()onMeasure

作为容器,RecyclerView 要干两件事,在 onMeasure() 中确定自己和孩子的尺寸,在 onLayout() 中布局孩子的位置

如果没指定 LayoutManager 或者它的宽高都是 MeasureSpec.EXACTLY 的,那么就跟普通 View 一样默认测量就行了

if (mLayout == null) {

defaultOnMeasure(widthSpec, heightSpec);

return;

}

if (mLayout.isAutoMeasureEnabled()) {

final int widthMode = MeasureSpec.getMode(widthSpec);

final int heightMode = MeasureSpec.getMode(heightSpec);

mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);

final boolean measureSpecModeIsExactly =

widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY;

if (measureSpecModeIsExactly || mAdapter == null) {

return;

}

if (mState.mLayoutStep == State.STEP_START) {

dispatchLayoutStep1();

}

mLayout.setMeasureSpecs(widthSpec, heightSpec);

mState.mIsMeasuring = true;

dispatchLayoutStep2();

mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);

if (mLayout.shouldMeasureTwice()) {

mLayout.setMeasureSpecs(

MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),

MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));

mState.mIsMeasuring = true;

dispatchLayoutStep2();

mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);

}

} else {

if (mHasFixedSize) {

mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);

return;

}

}

大部分 LayoutManagerisAutoMeasureEnabled() 都是 true,表示使用 RecyclerView 的 自动测量机制 进行测量,此时,LayoutManager#onMeasure(Recycler, State, int, int) 内部只是调用了 defaultOnMeasure(),不要重写这个方法。false 的话就得重写

第一步 dispatchLayoutStep1() 主要处理 Adapter 的更新和动画运行 processAdapterUpdatesAndSetAnimationF **《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》无偿开源 徽信搜索公众号【编程进阶路】** lags();,保存动画过程中的 View 状态 mViewInfoStore.addToPreLayout(holder, animationInfo);,必要的话还会预布局并保存信息 recordPreLayoutInformation()

第二步 dispatchLayoutStep2() 对孩子进行真正的测量和布局 mLayout.onLayoutChildren(mRecycler, mState);

你会发现 dispatchLayoutStep2() 可能被调用多次,你也会发现 dispatchLayoutStep1()dispatchLayoutStep2() 既有测量的功能也有布局的功能,虽然在 measure 里布局有点奇怪,但是在真正 layout 的时候能省这两步时间

[](()onLayout


onLayout() 中只是调用 dispatchLayout() 方法真正开始对子 View 进行布局

void dispatchLayout() {

if (mAdapter == null) {

Log.e(TAG, “No adapter attached; skipping layout”);

return;

}

if (mLayout == null) {

Log.e(TAG, “No layout manager attached; skipping layout”);

return;

}

mState.mIsMeasuring = false;

if (mState.mLayoutStep == State.STEP_START) {

dispatchLayoutStep1();

mLayout.setExactMeasureSpecsFrom(this);

dispatchLayoutStep2();

} else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()

|| mLayout.getHeight() != getHeight()) {

// First 2 steps are done in onMeasure but looks like we have to run again due to

// changed size.

mLayout.setExactMeasureSpecsFrom(this);

dispatchLayoutStep2();

} else {

// always make sure we sync them (to ensure mode is exact)

mLayout.setExactMeasureSpecsFrom(this);

}

dispatchLayoutStep3();

}

最后一步 dispatchLayoutStep3(); 记录并开始 View 动画 mViewInfoStore.process(mViewInfoProcessCallback);,然后做一些必要的清理工作

[](()onDraw

onDraw() 中只需要绘制 ItemDecoration 即可:

mItemDecorations.get(i).onDraw(c, this, mState);

但是对于边界装饰的绘制或者 ItemDecoration#onDrawOver() 的实现就要重写 draw() 方法了

mItemDecorations.get(i).onDrawOver(c, this, mState);

[](()缓存

在第二步布局时 dispatchLayoutStep2() 会调用 mLayout.onLayoutChildren(mRecycler, mState);,所以在 onLayoutChildren() 中完成 View 的获取

LinearLayoutManageronLayoutChildren() 为例,它的布局算法就是先检查孩子和其它变量,寻找锚点坐标,然后从尾到头的方向填充以及从头到尾的方向填充(fill()),然后滚动以满足需要

fill() 是一个神奇的方法,它可以在指定方向上填充满子 View

int fill(RecyclerView.Recycler recycler, LayoutState layoutState,

RecyclerView.State state, boolean stopOnFocusable) {

while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {

layoutChunk(recycler, state, layoutState, layoutChunkResult);

}

}

layoutChunk() 中就是取 View 的过程 View view = layoutState.next(recycler);

View next(RecyclerView.Recycler recycler) {

if (mScrapList != null) {

return nextViewFromScrapList();

}

final View view = recycler.getViewForPosition(mCurrentPosition);

mCurrentPosition += mItemDirection;

return view;

}

ViewHolder tryGetViewHolderForPositionByDeadline(int position,

boolean dryRun, long deadlineNs) {

if (mState.isPreLayout()) {

holder = getChangedScrapViewForPosition(position);

}

if (holder == null) {

holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);

}

if (holder == null) {

if (mAdapter.hasStableIds()) {

holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),

type, dryRun);

}

if (holder == null && mViewCacheExtension != null) {

final View view = mViewCacheExtension

.getViewForPositionAndType(this, position, type);

if (view != null) {

holder = getChildViewHolder(view);

}

}

if (holder == null) {

holder = getRecycledViewPool().getRecycledView(type);

}

if (holder == null) {

holder = mAdapter.createViewHolder(RecyclerView.this, type);

}

}

return holder;

}

ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {

final int scrapCount = mAttachedScrap.size();

for (int i = 0; i < scrapCount; i++) {

final ViewHolder holder = mAttachedScrap.get(i);

if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position

&& !holder.isInvalid() && (mState.mInPreLayout || !holder.isRemoved())) {

return holder;

}

}

if (!dryRun) {

View view = mChildHelper.findHiddenNonRemovedView(position);

if (view != null) {

final ViewHolder vh = getChildViewHolderInt(view);

mChildHelper.unhide(view);

mChildHelper.detachViewFromParent(layoutIndex);

scrapView(view);

return vh;

}

}

final int cacheSize = mCachedViews.size();

for (int i = 0; i < cacheSize; i++) {

final ViewHolder holder = mCachedViews.get(i);

if (!holder.isInvalid() && holder.getLayoutPosition() == position

&& !holder.isAttachedToTransitionOverlay()) {

if (!dryRun) {

mCachedViews.remove(i);

}

return holder;

}

}

return null;

}

所以取 ViewHolder(View) 的过程大体是这样的

  • getChangedScrapViewForPosition() isPreLayout

  • getScrapOrHiddenOrCachedHolderForPosition()

  • mAttachedScrap

  • findHiddenNonRemovedView()

  • mCachedViews

  • getScrapOrCachedViewForId() hasStableIds

  • getChildViewHolder() mViewCacheExtension

  • getRecycledViewPool().getRecycledView()

  • mAdapter.createViewHolder()

每次 layout 或者 scroll 的时候都会取 ViewHolder(View) 来更新 RecyclerView 的渲染(dispatchLayoutStep2() 最终会调用 fill()scrollBy() 最终也会调用 fill()fill() 就是不断地取 ViewHolder(View) 来填充满容器)

所以对于屏幕中已经有的 View 直接用即可,这就是 mAttachedScrapArrayList<ViewHolder> 类型的

对于动画过程中隐藏的 View 也可以直接用,这就是 mHiddenViewsList<View> 类型的

对于刚刚划出屏幕的 View 是可以马上拿过来直接用或复用,这就是 mCachedViewsArrayList<ViewHolder> 类型的

对于想要多个 RecyclerView 共享的 View,可以使用 RecycledViewPool(如果不显式指定的话每个 RecyclerView 都会创建自己的 RecycledViewPool),这个 RecycledViewPool 里会维护一个 SparseArray<ScrapData>,key 就是 viewType,值是 ArrayList<ViewHolder> 类型的

所以,真正的缓存(真正回收复用的缓存)有两个,一个是 mCachedViews,默认容量为 2,超过了就从头删(FIFO):

if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {

recycleCachedViewAt(0);

cachedViewSize–;

}

一个是 RecycledViewPool 中的 ScrapData,默认容量为 5,超过了直接丢弃:

if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {

return;

}

RecyclerView 缓存灵活的一点是可以通过 setViewCacheExtension 自定义 RecycledViewPool 前一级缓存

[](()RecyclerView 分析

RecyclerView 统一了传统滚动列表(ListView / GridView),并且做了完善,更灵活也更强大,尤其是对 View 的回收复用极大程度上避免了不必要的视图绑定过程。但是过分追求灵活,过分追求性能也暴露出了缺陷,比如说 RecyclerView 类自己本身的代码量就膨胀到几万行,代码注释中的 ugly, TODO, consider 等描述也是让人哭笑不得,设计的越复杂越容易出 Bug。而 RecyclerView 使用起来也不够简洁,绝大部分情况下列表都是简单的竖向的传统列表,LayoutManager 却不能缺省,忘写了也不会报错,分割线不能缺省也不能静态指定,Adapter 的模板代码也非常多

[](()RxJava 3.0.0


RxJava 是 ReactiveX 的 Java 实现,往高了说它提供了响应式和函数式编程范式,优雅地解决了异步和基于事件的编程问题,而实际上只是弥补了传统 Java 异步困难的设计缺陷。在传统 Java 中同步获取单个值是这样的 T getData(),同步获取多个值是这样的 Iterable<T> getData()。但是异步获取单个值却要开线程返回个包装类 Future<T> getData(),然后利用 Futureget() 方法才能拿到真正的值,而异步获取多个值好像只能这样了 Iterable<Future<T>> getData()。而问题是 Futureget() 方法是阻塞的,会阻塞之后代码的执行,这在逻辑稍微复杂(一个 Future 依赖另一个 Future)时阻塞会变成性能噩梦,而过多的回调和回调嵌套会变成回调地狱

所以,传统 Java 的 Future 在面对复杂异步操作时变得越来越无能为力,而 RxJava 的异步流正好弥补了这个缺陷,让所有的操作都是基于数据流的,异步对于流来说也仅仅是个操作符,逻辑一下子清晰了,代码一下子简洁了

[](()Observable

Observable 就是数据源,既可以同步也可以异步地发射数据,既可以发射单个值也可以发射多个值,它是个抽象类,所以需要通过它的 CreateJustFrom 等操作符来创建具体的 Observable:

Observable

.create(emitter -> {

emitter.onNext(“Hello World”);

emitter.onComplete();

})

.subscribe(System.out::println);

Create 操作符创建的是 ObservableCreateJust 创建的是 ObservableJust,它们根据自己的需要实现 subscribeActual() 方法,如 Create 的:

public final class ObservableCreate extends Observable {

@Override

protected void subscribeActual(Observer<? super T> observer) {

source.subscribe(parent);

}

}

source 就是我们传的用来发射数据的 ObservableOnSubscribeparent 就是封装了我们定义的观察者的 CreateEmitter。而 Just 的实现更简单,直接调用 observer.onNext(value);observer.onComplete();

[](()Observer

声明观察者很简单,onNext()onError()onComplete() 中处理到来的数据或事件,onSubscribe() 中进行取消订阅的处理

[](()subscribe

Observable 是一个异步 push 的数据流,所以每次订阅一个观察者时都调用 subscribeActual() 发射数据即可:

@Override

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ndroid系统源代码情景分析的评论 这本书是我看过的最深入的一本android书了,可以看出作者是一个很有悟性的程序员,很适合需要提高的android框架层工程师进阶。binder部分是目前所有书中分析的最全面的。匿名共享内存分析的也很好。 情况分析应该是学毛德操老师的,作者确实做到了,作者在讲解时,会从java层到native层,再到linux kernel中整个串起来讲。使读者可以完全了解某些子系统的运行机制 内容简介 · · · · · · 在内容上,本书结合使用情景,全面、深入、细致地分析Android系统的源代码,涉及到Linux内核层、硬件抽象层(HAL)、运行时库层(Runtime)、应用程序框架层(Application Framework)以及应用程序层(Application)。 在组织上,本书将上述内容划分为初识Android系统、Android专用驱动系统和Android应用程序框架三大篇章。初识Android系统篇介绍了参考书籍、基础知识以及实验环境搭建;Android专用驱动系统篇介绍了Logger日志驱动程序、Binder进程间通信驱动程序以及Ashmem匿名共享内存驱动程序;Android应用程序框架篇从组件、进程、消息以及安装四个维度来对Android应用程序的框架进行了深入的剖析。 通过上述内容及其组织,本书能使读者既能从整体上把握Android系统的层次结构,又能从细节上去掌握每一个层次的要点。 作者简介 · · · · · · 罗升阳,1984年出生,2007年毕业于浙江大学计算机系,取得学士学位,2010年毕业于上海交通大学计算机系,取得硕士学位。毕业后一直从事于互联网软件开发,并且致力于移动平台的研究,特别是对Android平台有深入的理解和研究。在国内知名IT技术社区CSDN上发表了数十篇高质量的Android系统原创性文章,并且开设博客专栏--《老罗的Android之旅》,积极与网友互动,深受大家喜爱,访问量一直居于前茅。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值