JDK动态代理

通过java.lang.reflect.Proxy可以实现动态代理,但是这种方式只能作用于接口,如果一个类没有接口则无法实现动态代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
//Interface是一个接口,InterfaceImpl是接口的实现类
val delegate = InterfaceImpl()
val proxy = Proxy.newProxyInstance(Interface::class.java.classLoader, arrayOf(Interface::class.java)
) { proxy, method, args ->
if (method.name == "testMethod") {
//可以打印日志等
}
if (args != null) {
method.invoke(delegate, *args)
} else {
method.invoke(delegate)
}
} as Interface

CGLIB实现动态代理

CGLIB通过动态生成一个代理类的子类来提供代理。但是对于final方法,是无法实现代理的。

参考

CGLIB(Code Generation Library) 介绍与原理
动态代理底层实现

阅读全文 »

本文创建了一个独立进程的service,通过bind方式来绑定服务,并通过binder与service进行交互。基于此来分析binder交互机制。

Service的创建与使用

定义aidl接口:

1
2
3
4
5
6
7
8
9
//IRemote.aidl
interface IRemote {
void setCallback(RemoteCallback callback);
}

//RemoteCallback.aidl
interface RemoteCallback {
void callback(String content);
}

IRemote是service的对外接口,TalkCallback则用于从service回调client端,加入TalkCallback是为了更好的理解service和client相互调用的流程。
定义完aidl后,编译一遍项目,这样就可以生成对应的java类,对应的java类在app/build/generated/aidl_source_output_dir目录下。

定义Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class RemoveService extends Service {
public RemoveService() {}

@Override
public IBinder onBind(Intent intent) {
return binder;
}

private final IBinder binder = new IRemote.Stub() {
@Override
public void setCallback(RemoteCallback callback) throws RemoteException {
//收到client端的函数调用,并回调client端
callback.callback("I'm Service");
}
};
}

因为我们要定义一个独立进程的service,所以在AndroidManifest.xml要声明android:process属性,如下:

1
2
3
4
5
<service
android:name=".RemoveService"
android:enabled="true"
android:exported="false"
android:process=":remote"/>

这样一个独立进程的service就定义完成了,然后就可以使用了。

阅读全文 »

先看下app端的类图结构:

WindowManagerWindowActivityPhoneWindowWindowManagerImpl«Singleton»WindowManagerGlobalViewParentViewRootImplIWindowSessionIWindow.StubViewRootImpl.WIWindowIWindowManagerSurfaceSurfaceControl1n

IWindowManager

IWindowManager在IWindowManager.aidl文件中定义,是WindowManagerService的对外接口。

IWindowManagerIWindowManager.StubBinderWindowManagerServiceIWindowSessionIWindowSession.StubSession

IWindowSession

每个app都会有一个Window Session用于与window manager进行交互。IWindowSession是通过aidl定义的binder接口,app通过IWindowSession与WMS进行交互。


zenuml
new ViewRootImpl() {
    WindowManagerGlobal.getWindowSession {
        //sWindowSession是WindowManagerGlobal的静态类变量
        //如果sWindowSession为空就通过WMS.openSession来打开一个
        if (sWindowSession == null) {
            WindowManagerService.openSession {
                new Session()
            }
        }
        return sWindowSession
    }
}

addWindow把IWindow加入到WMS

IWindow是一个binder接口,这个binder的service端是app,实现类是ViewRootImpl.W,client端是WMS。WMS会通过IWindow这个binder接口来通知app window相关的事件。先看下addWindow的调用时序:

阅读全文 »

现有项目添加C/C++源码

如果现有项目还不支持C/C++,则可以通过如下步骤来加入C/C++

Add C++ to Module

然后按照步骤操作即可。添加完成后打开app\src\main\cpp\CMakeLists.txt文件,修改项目名称

Java/Kotlin代码声明native函数

我们在me.rjy.android.demo.MainActivity中定义一个native函数,并加载native库。

Java代码:

1
2
3
4
5
6
7
public class MainActivity extends AppCompatActivity {
public native String stringFromJNI();

static {
System.loadLibrary("demo");
}
}

Kotlin代码:

1
2
3
4
5
6
7
8
class MainActivity : ComponentActivity() {
external fun stringFromJNI(): String

companion object {
init {
System.loadLibrary("demo")
}
}
阅读全文 »

本文以时序图的形式来展示activity的启动过程,相比于贴源码会更加直观。本文的讲解的流程是基于MainActivity使用standard模式启动SecondActivity,且两个Activity都在同一个应用中,最后的部分也会讲解一下进程的启动。

第一阶段:执行startActivity


zenuml
group App {
    <<App>> act as Activity
    <<App>> ins as Instrumentation
}
group AMS {
    <<AMS>> atms as ActivityTaskManagerService #F0F8FF
    ActivityStarter #F0F8FF
}
act.startActivity {
    act.startActivityForResult {
        ins.execStartActivity {
            atms.startActivity {
                atms.startActivityAsUser {
                    //没有缓存则创建
                    new ActivityStarter()
                    ActivityStarter."① execute"
                }
            }
        }
    }
}

zenuml
<<AMS>> ActivityStarter #F0F8FF
ActivityStarter."① execute" {
    executeRequest {
        new ActivityRecord()
        startActivityUnchecked {
            startActivityInner {
                Task.addChild
                Task.startActivityLocked
                RootWindowContainer.resumeFocusedTasksTopActivities {
                    Task.resumeTopActivityUncheckedLocked {
                        resumeTopActivityInnerLocked {
                            TaskFragment.resumeTopActivity {
                                //pause当前activity
                                "② startPausing()"
                                if (! isProcessRunning) {
                                    ActivityTaskManagerService.startProcessAsync
                                }
                            }
                        }
                    }
                }
            }
            handleStartResult
            postStartActivityProcessing
        }
    }
}

第二阶段:pause当前activity

启动SecondActivity之前会先执行MainActivitypause操作:

AMSAPPTaskFragmentTaskFragmentClientTransactionClientTransactionActivityRecordActivityRecordActivityThreadActivityThreadTransactionExecutorTransactionExecutorMainActivityMainActivity② startPausing()schedulePauseActivityPauseActivityItem.obtain()ClientLifecycleManager.scheduleTransactionobtainsetLifecycleStateRequest(PauseActivityItem)schedule()[ApplicationThread]→scheduleTransaction(this)scheduleTransactionsendMessage:EXECUTE_TRANSACTIONhandleMessage()execute(transaction)[PauseActivityItem]→execute()handlePauseActivityonPause()[PauseActivityItem]→postExecuteactivityPaused③ completePause

在Android 9之前的版本,ActivityThread中通过LAUNCH_ACTIVITY消息来启动activity,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
//android\app\ActivityThread.java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;

但从Andorid 9开始,ActivityThread去掉了LAUNCH_ACTIVITY PAUSE_ACTIVITY RESUME_ACTIVITY等消息,而是改成了EXECUTE_TRANSACTION,通过ClientTransaction这套机制来执行activity生命周期流程,相关源码如下:

阅读全文 »

Android View的整个绘制流程包含了3个阶段,分别是measure、layout、draw。measure用于计算View的宽高,结果放在mMeasuredWidthmMeasuredHeight中;layout的作用是计算view及其子view的位置;draw的作用就是将View真正的绘制到显示屏上。

当activity首次启动,或者更新View(如TextView重新设置text)时,都会走到ViewRootImpl.scheduleTraversals来触发View的渲染流程。


zenuml
ViewRootImpl.scheduleTraversals {
    "主线程消息循环插入同步屏障"
    Choreographer."postCallback:mTraversalRunnable" {
        scheduleFrameLocked {
            scheduleVsyncLocked {
                FrameDisplayEventReceiver.scheduleVsync()
            }
        }
    }
}
FrameDisplayEventReceiver.onVsync {
    Looper."发布一个同步消息"
}
Looper.run {
    Choreographer.doFrame {
        "doCallbacks(Choreographer.CALLBACK_INPUT, ...)"
        "doCallbacks(Choreographer.CALLBACK_ANIMATION,...)"
        "doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION,...)"
        "doCallbacks(Choreographer.CALLBACK_TRAVERSAL,...)" {
            ViewRootImpl."mTraversalBarrier.run" {
                ViewRootImpl.doTraversal {
                    "删除同步屏障"
                    performTraversals
                }
            }
        }
        "doCallbacks(Choreographer.CALLBACK_COMMIT,...)"
    }
}

zenuml
ViewRootImpl.performTraversals {
    measureHierarchy {
        performMeasure {
            DecorView.measure
        }
    }
    relayoutWindow {
        IWindowSession.relayout
        updateBlastSurfaceIfNeeded {
            new BLASTBufferQueue
            blastSurface = BLASTBufferQueue.createSurface
            "mSurface.transferFrom(blastSurface)"
        }
        ThreadedRenderer.setSurfaceControl
        ThreadedRenderer.setBlastBufferQueue
    }
    ThreadedRenderer.initialize {
        "HardwareRenderer.setSurface"
    }
    ThreadedRenderer.allocateBuffers
    ThreadedRenderer.setup
    performMeasure {
        DecorView.measure
    }
    performLayout {
        DecorView.layout
    }
    performDraw {
        draw {
            ThreadedRenderer.draw
        }
    }
}

关于relayoutWindow的调用流程可参考Android WindowManager与Window

参考:

draw() 流程

在自定义View中一般都会用到onDraw这个函数:


zenuml
ViewRootImpl.draw {
    if (isHardwareEnabled()) {
        ThreadedRenderer.draw
    } else {
        drawSoftware
    }
}
阅读全文 »

Bitmap内存分配

  • Android 2.3.3 (API level 10)以及更早的Android版本中,Bitmap的像素数据保存在native内存中,像素数据内存的回收则在finalize()中进行回收,存在很大的不确定性,很容易导致OOM的发生;
  • 从Android 3.0 (API level 11) 到Android 7.1 (API level 25),像素数据存放在Java Heap中,跟Bitmap对象一起回收。但由于图片是内存消耗大户,所以也很容易导致OOM,以及频繁的GC导致内存抖动问题。
  • 在Android 8.0 (API level 26)以及更高的版本中,像素数据保存在native heap中。通过一个辅助类NativeAllocationRegistry来实现native内存的回收。

在android.graphics.BitmapFactory类中有一系列函数可以解码生成Bitmap:

  • Bitmap decodeByteArray(byte[] data, int offset, int length)
  • Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts)
  • Bitmap decodeFile(String pathName)
  • Bitmap decodeFile(String pathName, Options opts)
  • …… 等等

这些方法都会调用到jni层frameworks\base\libs\hwui\jni\BitmapFactory.cpp,最终都会走到doDecode方法:

Android 12位图解码,使用native内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//frameworks\base\libs\hwui\jni\BitmapFactory.cpp
static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
jobject padding, jobject options, jlong inBitmapHandle,
jlong colorSpaceHandle) {
...... //代码省略
// Scale is necessary due to density differences.
if (scale != 1.0f) {
willScale = true;
scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f);
scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
}

android::Bitmap* reuseBitmap = nullptr;
unsigned int existingBufferSize = 0;
if (javaBitmap != nullptr) {
reuseBitmap = &bitmap::toBitmap(inBitmapHandle);
if (reuseBitmap->isImmutable()) {
ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
javaBitmap = nullptr;
reuseBitmap = nullptr;
} else {
existingBufferSize = reuseBitmap->getAllocationByteCount();
}
}

HeapAllocator defaultAllocator;
RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
SkBitmap::HeapAllocator heapAllocator;
SkBitmap::Allocator* decodeAllocator;
if (javaBitmap != nullptr && willScale) {
// This will allocate pixels using a HeapAllocator, since there will be an extra
// scaling step that copies these pixels into Java memory. This allocator
// also checks that the recycled javaBitmap is large enough.
decodeAllocator = &scaleCheckingAllocator;
} else if (javaBitmap != nullptr) {
decodeAllocator = &recyclingAllocator;
} else if (willScale || isHardware) {
// This will allocate pixels using a HeapAllocator,
// for scale case: there will be an extra scaling step.
// for hardware case: there will be extra swizzling & upload to gralloc step.
decodeAllocator = &heapAllocator;
} else {
decodeAllocator = &defaultAllocator;
}
......
SkBitmap decodingBitmap; //SkBitmap 是skia库中的类
//decodingBitmap.tryAllocPixels的作用是分配piexel内存,最终调用的是
//decodeAllocator->allocPixelRef(this);
if (!decodingBitmap.setInfo(bitmapInfo) ||
!decodingBitmap.tryAllocPixels(decodeAllocator)) {
return nullptr;
}

// Use SkAndroidCodec to perform the decode.
SkAndroidCodec::AndroidOptions codecOptions;
codecOptions.fZeroInitialized = decodeAllocator == &defaultAllocator ?
SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
codecOptions.fSampleSize = sampleSize;
//codec指的是SkAndroidCodec,是skia库中的类。下面这句代码就是真正的解码了
SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(),
decodingBitmap.rowBytes(), &codecOptions);

......
//按比例缩放位图
SkBitmap outputBitmap;
if (willScale) {
// Set the allocator for the outputBitmap.
SkBitmap::Allocator* outputAllocator;
if (javaBitmap != nullptr) {
outputAllocator = &recyclingAllocator;
} else {
outputAllocator = &defaultAllocator;
}

SkColorType scaledColorType = decodingBitmap.colorType();
// FIXME: If the alphaType is kUnpremul and the image has alpha, the
// colors may not be correct, since Skia does not yet support drawing
// to/from unpremultiplied bitmaps.
outputBitmap.setInfo(
bitmapInfo.makeWH(scaledWidth, scaledHeight).makeColorType(scaledColorType));
if (!outputBitmap.tryAllocPixels(outputAllocator)) {
// This should only fail on OOM. The recyclingAllocator should have
// enough memory since we check this before decoding using the
// scaleCheckingAllocator.
return nullObjectReturn("allocation failed for scaled bitmap");
}

SkPaint paint;
// kSrc_Mode instructs us to overwrite the uninitialized pixels in
// outputBitmap. Otherwise we would blend by default, which is not
// what we want.
paint.setBlendMode(SkBlendMode::kSrc);

SkCanvas canvas(outputBitmap, SkCanvas::ColorBehavior::kLegacy);
canvas.scale(scaleX, scaleY);
decodingBitmap.setImmutable(); // so .asImage() doesn't make a copy
canvas.drawImage(decodingBitmap.asImage(), 0.0f, 0.0f,
SkSamplingOptions(SkFilterMode::kLinear), &paint);
} else {
outputBitmap.swap(decodingBitmap);
}

......
//硬件位图
if (isHardware) {
//GPU中分配位图内存。原outputBitmap是否需要释放呢?在哪释放?
sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(outputBitmap);
if (!hardwareBitmap.get()) {
return nullObjectReturn("Failed to allocate a hardware bitmap");
}
//创建java层Bitmap,此处的hardwareBitmap.release()不是资源回收的意思,而是取出sk_sp中的Bitmap实例。
return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags,
ninePatchChunk, ninePatchInsets, -1);
}

// now create the java bitmap
return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
}

默认pixel内存分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
bool HeapAllocator::allocPixelRef(SkBitmap* bitmap) {
mStorage = android::Bitmap::allocateHeapBitmap(bitmap);
return !!mStorage;
}
//frameworks\base\libs\hwui\hwui\Bitmap.cpp
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
}
static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
const SkImageInfo& info = bitmap->info();
if (info.colorType() == kUnknown_SkColorType) {
LOG_ALWAYS_FATAL("unknown bitmap configuration");
return nullptr;
}

size_t size;

// we must respect the rowBytes value already set on the bitmap instead of
// attempting to compute our own.
const size_t rowBytes = bitmap->rowBytes();
if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) {
return nullptr;
}

auto wrapper = alloc(size, info, rowBytes); //使用入参的alloc函数分配内存
if (wrapper) {
wrapper->getSkBitmap(bitmap);
}
return wrapper;
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
void* addr = calloc(size, 1); //调用Linux C库函数分配内存
if (!addr) {
return nullptr;
}
return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes)); //返回最终的Bitmap对象
}

比例缩放或硬件位图场景内存分配

阅读全文 »

注解的使用场景可以分为两种:一)编译期间通过注解解析器处理;2)运行期间反射使用;

注解保留策略

  • RetentionPolicy.SOURCE : 编译期可见,但不会写入到.class文件;
  • RetentionPolicy#CLASS : 会写入到.class文件中,但是会被JVM忽略(这是默认策略);
  • RetentionPolicy#RUNTIME :注解会被写入到.class文件中,并且JVM运行期间也可见,可以通过反射放射获取到;

注解的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.CLASS)
public @interface MyClass {
String name();
}

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRuntime1 {
int id();
}

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRuntime2 {}

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface MySource {}

编译完成后,每个注解都会生成自己的.class文件,看一下MyClass这个注解的.class文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ javap -p -v me/demo/MyClass.class
Picked up JAVA_TOOL_OPTIONS: -Duser.language=en -Dfile.encoding=UTF-8
Classfile /F:/demo/JavaDemo/out/production/JavaDemo/me/demo/MyClass.class
Last modified Sep 21, 2023; size 472 bytes
MD5 checksum cb49d6b6a5ed7ab9c2b85d731996fb5f
Compiled from "MyClass.java"
public interface me.demo.MyClass extends java.lang.annotation.Annotation
minor version: 0
major version: 61
flags: (0x2601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT, ACC_ANNOTATION
this_class: #1 // me/demo/MyClass
super_class: #3 // java/lang/Object
interfaces: 1, fields: 0, methods: 1, attributes: 2
Constant pool:
#1 = Class #2 // me/demo/MyClass
#2 = Utf8 me/demo/MyClass
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Class #6 // java/lang/annotation/Annotation
#6 = Utf8 java/lang/annotation/Annotation
#7 = Utf8 name
#8 = Utf8 ()Ljava/lang/String;
#9 = Utf8 SourceFile
#10 = Utf8 MyClass.java
#11 = Utf8 RuntimeVisibleAnnotations
#12 = Utf8 Ljava/lang/annotation/Target;
#13 = Utf8 value
#14 = Utf8 Ljava/lang/annotation/ElementType;
#15 = Utf8 TYPE
#16 = Utf8 METHOD
#17 = Utf8 FIELD
#18 = Utf8 CONSTRUCTOR
#19 = Utf8 PARAMETER
#20 = Utf8 Ljava/lang/annotation/Retention;
#21 = Utf8 Ljava/lang/annotation/RetentionPolicy;
#22 = Utf8 CLASS
{
public abstract java.lang.String name();
descriptor: ()Ljava/lang/String;
flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "MyClass.java"
RuntimeVisibleAnnotations:
0: #12(#13=[e#14.#15,e#14.#16,e#14.#17,e#14.#18,e#14.#19])
java.lang.annotation.Target(
value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.METHOD,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.CONSTRUCTOR,Ljava/lang/annotation/ElementType;.PARAMETER]
)
1: #20(#13=e#21.#22)
java.lang.annotation.Retention(
value=Ljava/lang/annotation/RetentionPolicy;.CLASS
)

从MyClass.class文件第7行代码public interface MyClass extends java.lang.annotation.Annotation可以看出来MyClass实际上是继承自Annotation的接口类。这一点从java.lang.Class#getAnnotation这个方法也可以看出来:

1
2
3
4
5
6
//java/lang/Class.java
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);

return (A) annotationData().annotations.get(annotationClass);
}

注解的使用

阅读全文 »

Android Activity启动流程文章中已经介绍了,在activity的onResume之后,ViewRootImpl#setView(View view, WindowManager.LayoutParams attrs, ...),其中view就是DecorView,ViewRootImpl#setView中就会调用requestLayout,然后调用scheduleTraversals。这是首次调用,后续view的改动都会调用到scheduleTraversals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//android-12.1.0_r27\frameworks\base\core\java\android\view\ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
//添加同步屏障,主线程的同步消息都会进制执行,保证vsync信号到来时TraversalRunnable能够立刻被执行
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}

final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}

void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
//删除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}

performTraversals();

if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
阅读全文 »

ViewGroupRecyclerViewScrollingViewRecyclerArrayList<ViewHolder> mAttachedScrapArrayList<ViewHolder> mChangedScrapArrayList<ViewHolder> mCachedViewsRecycledViewPool mRecyclerPoolRecycledViewPool

删除View缓存使用图解

RecyclerView移除元素

在垂直布局的RecyclerView中展示了Item0~Item4这5个TextView,我们现在把Item2删掉。数据更新后,我们调用Adapter#notifyItemRemoved(2)来提交更新。

RecyclerView删除Item

dispatchLayoutStep1阶段:

  1. 调用detachViewFromParent把Item0~Item4这五个View从RecyclerView中detache掉,然后放入把ViewHolder放入mAttachedScrap进行缓存。ViewHodler都会被标记为FLAG_TMP_DETACHED,并且Item2会被标记为FLAG_REMOVED;
  2. 然后layout进行填充,把Item0~Item4从mAttachedScrap中取出,然后调用attachViewToParent重新加入到RecyclerView中。
  3. 调用onCreateViewHolder创建一个新ViewHolder(Item5),执行onBindViewHolder,并addView到RecyclerView中。

dispatchLayoutStep2阶段:

  1. 调用detachViewFromParent把Item0~Item5这六个View从RecyclerView中detache掉,然后把ViewHolder放入mAttachedScrap进行缓存。ViewHolder都会被标记为FLAG_TMP_DETACHED,并且Item2会被标记为FLAG_REMOVED;
  2. 除了Item2的ViewHolder之外,把其他ViewHolder从mAttachedScrap缓存中取出,然后调用attachViewToParent重新加入到RecyclerView中。

dispatchLayoutStep3阶段:

阅读全文 »
0%