Java动态代理
JDK动态代理
通过java.lang.reflect.Proxy
可以实现动态代理,但是这种方式只能作用于接口,如果一个类没有接口则无法实现动态代理。
1 | //Interface是一个接口,InterfaceImpl是接口的实现类 |
CGLIB实现动态代理
CGLIB通过动态生成一个代理类的子类来提供代理。但是对于final方法,是无法实现代理的。
通过java.lang.reflect.Proxy
可以实现动态代理,但是这种方式只能作用于接口,如果一个类没有接口则无法实现动态代理。
1 | //Interface是一个接口,InterfaceImpl是接口的实现类 |
CGLIB通过动态生成一个代理类的子类来提供代理。但是对于final方法,是无法实现代理的。
本文创建了一个独立进程的service,通过bind方式来绑定服务,并通过binder与service进行交互。基于此来分析binder交互机制。
定义aidl接口:
1 | //IRemote.aidl |
IRemote是service的对外接口,TalkCallback则用于从service回调client端,加入TalkCallback是为了更好的理解service和client相互调用的流程。
定义完aidl后,编译一遍项目,这样就可以生成对应的java类,对应的java类在app/build/generated/aidl_source_output_dir
目录下。
定义Service:
1 | public class RemoveService extends Service { |
因为我们要定义一个独立进程的service,所以在AndroidManifest.xml要声明android:process
属性,如下:
1 | <service |
这样一个独立进程的service就定义完成了,然后就可以使用了。
先看下app端的类图结构:
IWindowManager在IWindowManager.aidl
文件中定义,是WindowManagerService
的对外接口。
每个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 } }
IWindow
加入到WMSIWindow是一个binder接口,这个binder的service端是app,实现类是ViewRootImpl.W
,client端是WMS。WMS会通过IWindow这个binder接口来通知app window相关的事件。先看下addWindow的调用时序:
如果现有项目还不支持C/C++,则可以通过如下步骤来加入C/C++
然后按照步骤操作即可。添加完成后打开app\src\main\cpp\CMakeLists.txt
文件,修改项目名称
我们在me.rjy.android.demo.MainActivity
中定义一个native函数,并加载native库。
Java代码:
1 | public class MainActivity extends AppCompatActivity { |
Kotlin代码:
1 | class MainActivity : ComponentActivity() { |
本文以时序图的形式来展示activity的启动过程,相比于贴源码会更加直观。本文的讲解的流程是基于MainActivity
使用standard模式启动SecondActivity
,且两个Activity都在同一个应用中,最后的部分也会讲解一下进程的启动。
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 } } }
启动SecondActivity
之前会先执行MainActivity
的pause操作:
在Android 9之前的版本,ActivityThread
中通过LAUNCH_ACTIVITY
消息来启动activity,源码如下:
1 | //android\app\ActivityThread.java |
但从Andorid 9开始,ActivityThread
去掉了LAUNCH_ACTIVITY
PAUSE_ACTIVITY
RESUME_ACTIVITY
等消息,而是改成了EXECUTE_TRANSACTION,通过ClientTransaction这套机制来执行activity生命周期流程,相关源码如下:
Android View的整个绘制流程包含了3个阶段,分别是measure、layout、draw。measure用于计算View的宽高,结果放在mMeasuredWidth
和mMeasuredHeight
中;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
参考:
在自定义View中一般都会用到onDraw这个函数:
zenuml ViewRootImpl.draw { if (isHardwareEnabled()) { ThreadedRenderer.draw } else { drawSoftware } }
NativeAllocationRegistry
来实现native内存的回收。在android.graphics.BitmapFactory类中有一系列函数可以解码生成Bitmap:
这些方法都会调用到jni层frameworks\base\libs\hwui\jni\BitmapFactory.cpp
,最终都会走到doDecode
方法:
1 | //frameworks\base\libs\hwui\jni\BitmapFactory.cpp |
1 | bool HeapAllocator::allocPixelRef(SkBitmap* bitmap) { |
注解的使用场景可以分为两种:一)编译期间通过注解解析器处理;2)运行期间反射使用;
RetentionPolicy.SOURCE
: 编译期可见,但不会写入到.class文件;RetentionPolicy#CLASS
: 会写入到.class文件中,但是会被JVM忽略(这是默认策略);RetentionPolicy#RUNTIME
:注解会被写入到.class文件中,并且JVM运行期间也可见,可以通过反射放射获取到;1 | @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) |
编译完成后,每个注解都会生成自己的.class文件,看一下MyClass这个注解的.class文件的内容:
1 | $ javap -p -v me/demo/MyClass.class |
从MyClass.class文件第7行代码public interface MyClass extends java.lang.annotation.Annotation
可以看出来MyClass实际上是继承自Annotation的接口类。这一点从java.lang.Class#getAnnotation
这个方法也可以看出来:
1 | //java/lang/Class.java |
在Android Activity启动流程文章中已经介绍了,在activity的onResume之后,ViewRootImpl#setView(View view, WindowManager.LayoutParams attrs, ...)
,其中view就是DecorView,ViewRootImpl#setView中就会调用requestLayout
,然后调用scheduleTraversals
。这是首次调用,后续view的改动都会调用到scheduleTraversals
。
1 | //android-12.1.0_r27\frameworks\base\core\java\android\view\ViewRootImpl.java |
在垂直布局的RecyclerView中展示了Item0~Item4这5个TextView,我们现在把Item2删掉。数据更新后,我们调用Adapter#notifyItemRemoved(2)
来提交更新。
dispatchLayoutStep1阶段:
dispatchLayoutStep2阶段:
dispatchLayoutStep3阶段: