Android应用程序窗口设计框架二

handleResumeActivity

performLaunchActivity函数完成了两件事:

1) Activity窗口对象的创建,通过attach函数来完成;

2) Activity视图对象的创建,通过setContentView函数来完成;

这些准备工作完成后,就可以显示该Activity了,应用程序进程通过调用handleResumeActivity函数来启动Activity的显示过程。

frameworks\base\core\java\android\app\ ActivityThread.java

?
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
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
     unscheduleGcIdler();
     ActivityClientRecord r;
     try {
         ①r = performResumeActivity(token, clearHide);
     } catch (Exception e) {
         ...
     }
     if (r != null ) {
         final Activity a = r.activity;
         ...
         if (r.window == null && !a.mFinished && willBeVisible) {
             //获得为当前Activity创建的窗口PhoneWindow对象
             r.window = r.activity.getWindow();
             //获取为窗口创建的视图DecorView对象
             View decor = r.window.getDecorView();
             decor.setVisibility(View.INVISIBLE);
             //在attach函数中就为当前Activity创建了WindowManager对象
             ViewManager wm = a.getWindowManager();
             //得到该视图对象的布局参数
             ②WindowManager.LayoutParams l = r.window.getAttributes();
             //将视图对象保存到Activity的成员变量mDecor中
             a.mDecor = decor;
             l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
             if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
                 l.idleScreenAvailable = true ;
             } else {
                 l.idleScreenAvailable = false ;
             }
             l.softInputMode |= forwardBit;
             if (a.mVisibleFromClient) {
                 a.mWindowAdded = true ;
                 //将创建的视图对象DecorView添加到Activity的窗口管理器中
                 ③wm.addView(decor, l);
             }
         } else if (!willBeVisible) {
             ...
         }
         ...
         if (!r.onlyLocalRequest) {
             r.nextIdle = mNewActivities;
             mNewActivities = r;
             Looper.myQueue().addIdleHandler( new Idler());
         }
         ...
     } else {
         ...
     }
}

我们知道,在前面的performLaunchActivity函数中完成Activity的创建后,会将当前当前创建的Activity在应用程序进程端的描述符ActivityClientRecord以键值对的形式保存到ActivityThread的成员变量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份证,即是IApplicationToken.Proxy代理对象,也用于与AMS通信。上面的函数首先通过performResumeActivity从mActivities变量中取出Activity的应用程序端描述符ActivityClientRecord,然后取出前面为Activity创建的视图对象DecorView和窗口管理器WindowManager,最后将视图对象添加到窗口管理器中。

\

我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager

frameworks\base\core\java\android\view\ Window.java

?
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
public final void addView(View view, ViewGroup.LayoutParams params) {
     WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
     CharSequence curTitle = wp.getTitle();
     //应用程序窗口
     if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
         wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
         if (wp.token == null ) {
             View decor = peekDecorView();
             if (decor != null ) {
                 // LayoutParams 的token设置为W本地Binder对象
                 wp.token = decor.getWindowToken();
             }
         }
         if (curTitle == null || curTitle.length() == 0 ) {
             //根据窗口类型设置不同的标题
            
             if (mAppName != null ) {
                 title += ":" + mAppName;
             }
             wp.setTitle(title);
         }
     } else { //系统窗口
         if (wp.token == null ) {
             wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
         }
         if ((curTitle == null || curTitle.length() == 0 )
                 && mAppName != null ) {
             wp.setTitle(mAppName);
         }
     }
     if (wp.packageName == null ) {
         wp.packageName = mContext.getPackageName();
     }
     if (mHardwareAccelerated) {
         wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
     }
     super .addView(view, params);
}

LocalWindowManager的addView函数对不同类型窗口的布局参数进行相应的设置,比如布局参数中的token设置,如果是应用程序窗口,则设置token为W本地Binder对象。如果不是应用程序窗口,同时当前窗口没有父窗口,则设置token为当前窗口的IApplicationToken.Proxy代理对象,否则设置为父窗口的IApplicationToken.Proxy代理对象。最后视图组件的添加工作交给其父类来完成。LocalWindowManager继承于CompatModeWrapper,是WindowManagerImpl的内部类。

frameworks\base\core\java\android\view\WindowManagerImpl.java

?
1
2
3
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
     mWindowManager.addView(view, params, mCompatibilityInfo);
}

前面我们介绍了,每一个Activity拥有一个轻量级窗口管理器,通过轻量级窗口管理器LocalWindowManager来访问重量级窗口管理器WindowManagerImpl,因此视图组件的添加过程又转交给了WindowManagerImpl来实现。

?
1
2
3
public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
     addView(view, params, cih, false );
}

该函数又调用WindowManagerImpl的另一个重载函数来添加视图组件

?
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
private void addView(View view, ViewGroup.LayoutParams params,
         CompatibilityInfoHolder cih, boolean nest) {
     ...
     final WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
     ViewRootImpl root;
     View panelParentView = null ;
     synchronized ( this ) {
         ...
         //从mViews中查找当前添加的View
         int index = findViewLocked(view, false );
         //如果已经存在,直接返回
         if (index >= 0 ) {
             ...
             return ;
         }
         //尚未添加当前View
         if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
             final int count = mViews != null ? mViews.length : 0 ;
             for ( int i= 0 ; i<count; i++)= "" {= "" if = "" (mroots[i].mwindow.asbinder()= "=" wparams.token)= "" panelparentview= "mViews[i];" }= "" 为activity创建一个viewrootimpl对象= "" ①root= "new" viewrootimpl(view.getcontext());= "" ...= "" 设置视图组件的布局参数= "" view.setlayoutparams(wparams);= "" (mviews= "=" null )= "" index= "1;" mviews= "new" view[ 1 ];= "" mroots= "new" viewrootimpl[ 1 ];= "" mparams= "new" windowmanager.layoutparams[ 1 ];= "" else = "" 动态增加mviews数组长度= "" += "" 1 ;= "" object[]= "" old= "mViews;" view[index];= "" system.arraycopy(old,= "" 0 ,= "" mviews,= "" index- 1 );= "" 动态增加mroots数组长度= "" viewrootimpl[index];= "" mroots,= "" 动态增加mparams数组长度= "" windowmanager.layoutparams[index];= "" mparams,= "" index--;= "" ②mviews[index]= "view;" mroots[index]= "root;" mparams[index]= "wparams;" try = "" ③root.setview(view,= "" wparams,= "" panelparentview);= "" catch = "" (runtimeexception= "" e)= "" <= "" pre= "" >
<p>到此我们知道,当应用程序向窗口管理器中添加一个视图对象时,首先会为该视图对象创建一个ViewRootImpl对象,并且将视图对象、ViewRootImpl对象、视图布局参数分别保存到窗口管理器WindowManagerImpl得mViews、mRoots、mParams数组中,如下图所示:</p>
<p><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183231.jpg" width="673" height="370" style="width: 630px; height: 344.271844660194px;"><br>
<br>
</p>
<p>最后通过ViewRootImpl对象来完成视图的显示过程。</p>
<h3>ViewRootImpl构造过程</h3>
<p>frameworks\base\core\java\android\view\ViewRootImpl.java</p>
<pre class = "brush:java;" > public ViewRootImpl(Context context) {
     ...
     ①getWindowSession(context.getMainLooper());
     mThread = Thread.currentThread();
     mLocation = new WindowLeaked( null );
     mLocation.fillInStackTrace();
     mWidth = - 1 ;
     mHeight = - 1 ;
     mDirty = new Rect();
     mTempRect = new Rect();
     mVisRect = new Rect();
     mWinFrame = new Rect();
     ②mWindow = new W( this );
     mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
     mInputMethodCallback = new InputMethodCallback( this );
     mViewVisibility = View.GONE;
     mTransparentRegion = new Region();
     mPreviousTransparentRegion = new Region();
     mFirst = true ; // true for the first time the view is added
     mAdded = false ;
     mAccessibilityManager = AccessibilityManager.getInstance(context);
     mAccessibilityInteractionConnectionManager =
         new AccessibilityInteractionConnectionManager();
     mAccessibilityManager.addAccessibilityStateChangeListener(
             mAccessibilityInteractionConnectionManager);
     ③mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this , mHandler, this );
     mViewConfiguration = ViewConfiguration.get(context);
     mDensity = context.getResources().getDisplayMetrics().densityDpi;
     mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
     mProfileRendering = Boolean.parseBoolean(
             SystemProperties.get(PROPERTY_PROFILE_RENDERING, "false" ));
     ④mChoreographer = Choreographer.getInstance();
     PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
     mAttachInfo.mScreenOn = powerManager.isScreenOn();
     loadSystemProperties();
}</pre>
<p>在ViewRootImpl的构造函数中初始化了一些成员变量,ViewRootImpl创建了以下几个主要对象:</p>
<p> 1 )        通过getWindowSession(context.getMainLooper())得到IWindowSession的代理对象,该对象用于和WMS通信。</p>
<p> 2 )        创建了一个W本地Binder对象,用于WMS通知应用程序进程。</p>
<p> 3 )        采用单例模式创建了一个Choreographer对象,用于统一调度窗口绘图。</p>
<p> 4 )        创建ViewRootHandler对象,用于处理当前视图消息。</p>
<p> 5 )        构造一个AttachInfo对象;</p>
<p> 6 )        创建Surface对象,用于绘制当前视图,当然该Surface对象的真正创建是由WMS来完成的,只不过是WMS传递给应用程序进程的。</p>
<pre class = "brush:java;" > private final Surface mSurface = new Surface();
final ViewRootHandler mHandler = new ViewRootHandler();
</pre>
<p><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183232.jpg" width="672" height="368" style="width: 630px; height: 336.814404432133px;"><br>
</p>
<h4>IWindowSession代理获取过程</h4>
<p>frameworks\base\core\java\android\view\ViewRootImpl.java</p>
<pre class = "brush:java;" > public static IWindowSession getWindowSession(Looper mainLooper) {
     synchronized (mStaticInit) {
         if (!mInitialized) {
             try {
                 //获取输入法管理器
                 InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
                 //获取窗口管理器
                 IWindowManager windowManager = Display.getWindowManager();
                 //得到IWindowSession代理对象
                 sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());
                 float animatorScale = windowManager.getAnimationScale( 2 );
                 ValueAnimator.setDurationScale(animatorScale);
                 mInitialized = true ;
             } catch (RemoteException e) {
             }
         }
         return sWindowSession;
     }
}
</pre>
<p>以上函数通过WMS的openSession函数创建应用程序与WMS之间的连接通道,即获取IWindowSession代理对象,并将该代理对象保存到ViewRootImpl的静态成员变量sWindowSession中</p>
<pre class = "brush:java;" > static IWindowSession sWindowSession;</pre>
<p>因此在应用程序进程中有且只有一个IWindowSession代理对象。</p>
<p>frameworks\base\services\java\com\android\server\wm\WindowManagerService.java</p>
<pre class = "brush:java;" > public IWindowSession openSession(IInputMethodClient client,
         IInputContext inputContext) {
     if (client == null ) throw new IllegalArgumentException( "null client" );
     if (inputContext == null ) throw new IllegalArgumentException( "null inputContext" );
     Session session = new Session( this , client, inputContext);
     return session;
}
</pre>
<p>在WMS服务端构造了一个Session实例对象。</p>
<p><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183333.jpg" width="691" height="101" style="width: 630px; height: 91.7307692307692px;"><br>
</p>
<h4>AttachInfo构造过程</h4>
<p>frameworks\base\core\java\android\view\ View.java </p>
<pre class = "brush:java;" >AttachInfo(IWindowSession session, IWindow window,
         ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
     mSession = session; //IWindowSession代理对象,用于与WMS通信
     mWindow = window; //W对象
     mWindowToken = window.asBinder(); //W本地Binder对象
     mViewRootImpl = viewRootImpl; //ViewRootImpl实例
     mHandler = handler; //ViewRootHandler对象
     mRootCallbacks = effectPlayer; //ViewRootImpl实例
}
</pre>
<h4>Choreographer机制</h4>
<p>在Android4. 1 之后增加了Choreographer机制,用于同Vsync机制配合,实现统一调度界面绘图.</p>
<h5>Choreographer构造过程</h5>
<p>frameworks\base\core\java\android\view\Choreographer.java</p>
<pre class = "brush:java;" > public static Choreographer getInstance() {
     return sThreadInstance.get();
}
</pre><pre class = "brush:java;" > private static final ThreadLocal<choreographer> sThreadInstance =
         new ThreadLocal<choreographer>() {
     @Override
     protected Choreographer initialValue() {
         Looper looper = Looper.myLooper();
         if (looper == null ) {
             throw new IllegalStateException( "The current thread must have a looper!" );
         }
         return new Choreographer(looper);
     }
};
</choreographer></choreographer></pre>
<p>为调用线程创建一个Choreographer实例,调用线程必须具备消息循环功能,因为ViewRootImpl对象的构造是在应用程序进程的UI主线程中执行的,因此创建的Choreographer对象将使用UI线程消息队列。</p>
<pre class = "brush:java;" > private Choreographer(Looper looper) {
     mLooper = looper;
     //创建消息处理Handler
     mHandler = new FrameHandler(looper);
     //如果系统使用了Vsync机制,则注册一个FrameDisplayEventReceiver接收器
     mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null ;
     mLastFrameTimeNanos = Long.MIN_VALUE;
     //屏幕刷新周期
     mFrameIntervalNanos = ( long )( 1000000000 /
             new Display(Display.DEFAULT_DISPLAY, null ).getRefreshRate());
     //创建回调数组
     mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1 ];
     //初始化数组
     for ( int i = 0 ; i <= CALLBACK_LAST; i++) {
         mCallbackQueues[i] = new CallbackQueue();
     }
}
</pre>
<p>变量USE_VSYNC用于表示系统是否是用了Vsync同步机制,该值是通过读取系统属性debug.choreographer.vsync来获取的。如果系统使用了Vsync同步机制,则创建一个FrameDisplayEventReceiver对象用于请求并接收Vsync事件,最后Choreographer创建了一个大小为 3 的CallbackQueue队列数组,用于保存不同类型的Callback。</p>
<h5>添加回调过程</h5>
<p>frameworks\base\core\java\android\view\Choreographer.java</p>
<pre class = "brush:java;" > public void postCallback( int callbackType, Runnable action, Object token) {
     postCallbackDelayed(callbackType, action, token, 0 );
}
</pre>
<p> </p>
<pre class = "brush:java;" > public void postCallbackDelayed( int callbackType,
         Runnable action, Object token, long delayMillis) {
     if (action == null ) {
         throw new IllegalArgumentException( "action must not be null" );
     }
     if (callbackType < 0 || callbackType > CALLBACK_LAST) {
         throw new IllegalArgumentException( "callbackType is invalid" );
     }
     postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
</pre>
<p> </p>
<pre class = "brush:java;" > private void postCallbackDelayedInternal( int callbackType,
         Object action, Object token, long delayMillis) {
     synchronized (mLock) {
         final long now = SystemClock.uptimeMillis();
         final long dueTime = now + delayMillis;
         //将要执行的回调封装成CallbackRecord对象,保存到mCallbackQueues数组中
         mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
         //函数执行时间到
         if (dueTime <= now) {
             scheduleFrameLocked(now);
         } else { //通过异步消息方式实现函数延时执行
             Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
             msg.arg1 = callbackType;
             msg.setAsynchronous( true );
             mHandler.sendMessageAtTime(msg, dueTime);
         }
     }
}
</pre>
<p> </p>
<pre class = "brush:java;" > private final class FrameHandler extends Handler {
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
             case MSG_DO_SCHEDULE_CALLBACK:
                 doScheduleCallback(msg.arg1);
                 break ;
         }
     }
}
</pre>
<p> </p>
<pre class = "brush:java;" > void doScheduleCallback( int callbackType) {
     synchronized (mLock) {
         if (!mFrameScheduled) {
             final long now = SystemClock.uptimeMillis();
             if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                 scheduleFrameLocked(now);
             }
         }
     }
}
</pre>
<p> </p>
<pre class = "brush:java;" > private void scheduleFrameLocked( long now) {
     if (!mFrameScheduled) {
         mFrameScheduled = true ;
         //检查是否使用了Vsync机制
         if (USE_VSYNC) {
             //如果当前线程具备消息循环,则直接请求VSync信号
             if (isRunningOnLooperThreadLocked()) {
                 scheduleVsyncLocked();
             } else { //如果当前线程不具备消息循环,则通过主线程请求VSync信号
                 Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                 msg.setAsynchronous( true );
                 mHandler.sendMessageAtFrontOfQueue(msg);
             }
         } else { //如果系统没有使用VSync机制,则使用异步消息延时执行屏幕刷新
             final long nextFrameTime = Math.max(
                     mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
             Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
             msg.setAsynchronous( true );
             mHandler.sendMessageAtTime(msg, nextFrameTime);
         }
     }
}
</pre>
<p>在该函数中考虑了两种情况,一种是系统没有使用Vsync机制,在这种情况下,首先根据屏幕刷新频率计算下一次刷新时间,通过异步消息方式延时执行doFrame()函数实现屏幕刷新。如果系统使用了Vsync机制,并且当前线程具备消息循环,则直接请求Vsync信号,否则就通过主线程来请求Vsync信号。FrameDisplayEventReceiver对象用于请求并接收Vsync信号,当Vsync信号到来时,系统会自动调用其onVsync()函数,在该回调函数中执行doFrame()实现屏幕刷新。</p>
<p align= "center" ><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183334.jpg" style="height: 560px; width: 434.255874673629px;"></p>
<p>当VSYNC信号到达时,Choreographer doFrame()函数被调用</p>
<pre class = "brush:java;" > void doFrame( long frameTimeNanos, int frame) {
     final long startNanos;
     synchronized (mLock) {
         if (!mFrameScheduled) {
             return ; // no work to do
         }
         //保存起始时间
         startNanos = System.nanoTime();
         //由于Vsync事件处理采用的是异步方式,因此这里计算消息发送与函数调用开始之间所花费的时间
         final long jitterNanos = startNanos - frameTimeNanos;
         //如果线程处理该消息的时间超过了屏幕刷新周期
         if (jitterNanos >= mFrameIntervalNanos) {
             //计算函数调用期间所错过的帧数
             final long skippedFrames = jitterNanos / mFrameIntervalNanos;
             if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
                 Log.i(TAG, "Skipped " + skippedFrames + " frames!  "
                         + "The application may be doing too much work on its main thread." );
             }
             final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
             frameTimeNanos = startNanos - lastFrameOffset;
         }
         //如果frameTimeNanos小于一个屏幕刷新周期,则重新请求VSync信号
         if (frameTimeNanos < mLastFrameTimeNanos) {
             scheduleVsyncLocked();
             return ;
         }
         mFrameScheduled = false ;
         mLastFrameTimeNanos = frameTimeNanos;
     }
     //分别回调CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL事件
     doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
     doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
     doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
}
</pre>
<p align= "center" ><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183335.jpg" style="width: 627px; height: 187px;"></p>
<p><br>
Choreographer类中分别定义了CallbackRecord、CallbackQueue内部类,CallbackQueue是一个按时间先后顺序保存CallbackRecord的单向循环链表。</p>
<p align= "center" ><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183336.jpg" style="width: 495px; height: 138px;"></p>
<p>在Choreographer中定义了三个CallbackQueue队列,用数组mCallbackQueues表示,用于分别保存CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL这三种类型的Callback,当调用Choreographer类的postCallback()函数时,就是往指定类型的CallbackQueue队列中通过addCallbackLocked()函数添加一个CallbackRecord项:首先构造一个CallbackRecord对象,然后按时间先后顺序插入到CallbackQueue链表中。从代码注释中,我们可以知道CALLBACK_INPUT是指输入回调,该回调优先级最高,首先得到执行,而CALLBACK_TRAVERSAL是指处理布局和绘图的回调,只有在所有异步消息都执行完后才得到执行,CALLBACK_ANIMATION是指动画回调,比CALLBACK_TRAVERSAL优先执行,从doFrame()函数中的doCallbacks调用就能印证这点。</p>
<pre class = "brush:java;" >doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
</pre>
<p>当Vsync事件到来时,顺序执行CALLBACK_INPUT、CALLBACK_ANIMATION和CALLBACK_TRAVERSAL对应CallbackQueue队列中注册的回调。</p>
<pre class = "brush:java;" > void doCallbacks( int callbackType, long frameTimeNanos) {
     CallbackRecord callbacks;
     synchronized (mLock) {
         final long now = SystemClock.uptimeMillis();
         //从指定类型的CallbackQueue队列中查找执行时间到的CallbackRecord
         callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
         if (callbacks == null ) {
             return ;
         }
         mCallbacksRunning = true ;
     }
     try {
         //由于CallbackQueues是按时间先后顺序排序的,因此遍历执行所有时间到的CallbackRecord
         for (CallbackRecord c = callbacks; c != null ; c = c.next) {
             c.run(frameTimeNanos);
         }
     } finally {
         synchronized (mLock) {
             mCallbacksRunning = false ;
             do {
                 final CallbackRecord next = callbacks.next;
                 recycleCallbackLocked(callbacks);
                 callbacks = next;
             } while (callbacks != null );
         }
     }
}
</pre>
<p>该函数就是按时间顺序先后执行到时的CallbackRecord</p>
<pre class = "brush:java;" > private static final class CallbackRecord {
     public CallbackRecord next;
     public long dueTime;
     public Object action; // Runnable or FrameCallback
     public Object token;
 
     public void run( long frameTimeNanos) {
         if (token == FRAME_CALLBACK_TOKEN) {
             ((FrameCallback)action).doFrame(frameTimeNanos);
         } else {
             ((Runnable)action).run();
         }
     }
}
</pre>
<p>我们知道Choreographer对外提供了两个接口函数用于注册指定的Callback,postCallback()用于注册Runnable对象,而postFrameCallback()函数用于注册FrameCallback对象,无论注册的是Runnable对象还是FrameCallback对象,在CallbackRecord对象中统一装箱为Object类型。在执行其回调函数时,就需要区别这两种对象类型,如果注册的是Runnable对象,则调用其run()函数,如果注册的是FrameCallback对象,则调用它的doFrame()函数。</p>
<p align= "center" ><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183337.jpg" style="width: 485px; height: 288px;"></p>
<h5>Vsync请求过程</h5>
<p>我们知道在Choreographer构造函数中,构造了一个FrameDisplayEventReceiver对象,用于请求并接收Vsync信号,Vsync信号请求过程如下:</p>
<pre class = "brush:java;" > private void scheduleVsyncLocked() {
     //申请Vsync信号
     mDisplayEventReceiver.scheduleVsync();
}</pre>
<p>FrameDisplayEventReceiver继承于DisplayEventReceiver类,Vsync请求在DisplayEventReceiver中实现。</p>
<p>frameworks\base\core\java\android\view\ DisplayEventReceiver.java </p>
<pre class = "brush:java;" > public void scheduleVsync() {
     if (mReceiverPtr == 0 ) {
         Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                 + "receiver has already been disposed." );
     } else {
         //通过Jni方式调用native层的NativeDisplayEventReceiver对象来请求VSync
         nativeScheduleVsync(mReceiverPtr);
     }
}
</pre>
<p>frameworks\base\core\jni\ android_view_DisplayEventReceiver.cpp</p>
<pre class = "brush:java;" > static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) {
     //得到NativeDisplayEventReceiver对象指针
     sp<nativedisplayeventreceiver> receiver =
             reinterpret_cast<nativedisplayeventreceiver*>(receiverPtr);
     //通过NativeDisplayEventReceiver请求VSync
     status_t status = receiver->scheduleVsync();
     if (status) {
         String8 message;
         message.appendFormat( "Failed to schedule next vertical sync pulse.  status=%d" , status);
         jniThrowRuntimeException(env, message.string());
     }
}
</nativedisplayeventreceiver*></nativedisplayeventreceiver></pre>
<p align= "left" > </p>
<pre class = "brush:java;" >status_t NativeDisplayEventReceiver::scheduleVsync() {
     if (!mWaitingForVsync) {
         ALOGV( "receiver %p ~ Scheduling vsync." , this );
         // Drain all pending events.
         nsecs_t vsyncTimestamp;
         uint32_t vsyncCount;
         readLastVsyncMessage(&vsyncTimestamp, &vsyncCount);
         status_t status = mReceiver.requestNextVsync();
         if (status) {
             ALOGW( "Failed to request next vsync, status=%d" , status);
             return status;
         }
         mWaitingForVsync = true ;
     }
     return OK;
}
</pre>
<p align= "left" >VSync请求过程又转交给了DisplayEventReceiver</p>
<p>frameworks\ native \libs\gui\ DisplayEventReceiver.cpp </p>
<pre class = "brush:java;" >status_t DisplayEventReceiver::requestNextVsync() {
     if (mEventConnection != NULL) {
         mEventConnection->requestNextVsync();
         return NO_ERROR;
     }
     return NO_INIT;
}
</pre>
<p>这里又通过IDisplayEventConnection接口来请求Vsync信号,IDisplayEventConnection实现了Binder通信框架,可以跨进程调用,因为Vsync信号请求进程和Vsync产生进程有可能不在同一个进程空间,因此这里就借助IDisplayEventConnection接口来实现。下面通过图来梳理Vsync请求的调用流程:</p>
<p align= "center" ><img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183338.png" style="width: 231px; height: 241px;"></p>
<h3>视图View添加过程</h3>
<p>窗口管理器WindowManagerImpl为当前添加的窗口创建好各种对象后,调用ViewRootImpl的setView函数向WMS服务添加一个窗口对象。</p>
<pre class = "brush:java;" > public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
     synchronized ( this ) {
         if (mView == null ) {
             //将DecorView保存到ViewRootImpl的成员变量mView中
             mView = view;
             mFallbackEventHandler.setView(view);
             mWindowAttributes.copyFrom(attrs);
             attrs = mWindowAttributes;
             mClientWindowLayoutFlags = attrs.flags;
             setAccessibilityFocus( null , null );
             //DecorView实现了RootViewSurfaceTaker接口
             if (view instanceof RootViewSurfaceTaker) {
                 mSurfaceHolderCallback =
                         ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                 if (mSurfaceHolderCallback != null ) {
                     mSurfaceHolder = new TakenSurfaceHolder();
                     mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                 }
             }
             ...
             //同时将DecorView保存到mAttachInfo中
             mAttachInfo.mRootView = view;
             mAttachInfo.mScalingRequired = mTranslator != null ;
             mAttachInfo.mApplicationScale = mTranslator == null ? 1 .0f : mTranslator.applicationScale;
             if (panelParentView != null ) {
                 mAttachInfo.mPanelParentWindowToken
                         = panelParentView.getApplicationWindowToken();
             }
             ...
             //在添加窗口前进行UI布局
             ①requestLayout();
             if ((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0 ) {
                 mInputChannel = new InputChannel();
             }
             try {
                 mOrigWindowType = mWindowAttributes.type;
                 mAttachInfo.mRecomputeGlobalAttributes = true ;
                 collectViewAttributes();
                 //将窗口添加到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后,变为IWindow代理对象
                 ②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
                         getHostVisibility(), mAttachInfo.mContentInsets,
                         mInputChannel);
             } catch (RemoteException e) {
                 ...
             }
             ...
             //建立窗口消息通道
             if (view instanceof RootViewSurfaceTaker) {
                 mInputQueueCallback =
                     ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
             }
             if (mInputChannel != null ) {
                 if (mInputQueueCallback != null ) {
                     mInputQueue = new InputQueue(mInputChannel);
                     mInputQueueCallback.onInputQueueCreated(mInputQueue);
                 } else {
                     mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,Looper.myLooper());
                 }
             }
             ...
         }
     }
}
</pre>
<p align= "left" >通过前面的分析可以知道,用户自定义的UI作为一个子View被添加到DecorView中,然后将顶级视图DecorView添加到应用程序进程的窗口管理器中,窗口管理器首先为当前添加的View创建一个ViewRootImpl对象、一个布局参数对象ViewGroup.LayoutParams,然后将这三个对象分别保存到当前应用程序进程的窗口管理器WindowManagerImpl中,最后通过ViewRootImpl对象将当前视图对象注册到WMS服务中。<br>
<img alt= "\" src=" http: //www.2cto.com/uploadfile/Collfiles/20140702/2014070208183339.jpg" width="676" height="517" style="width: 630px; height: 468.125px;"></p>
<p>ViewRootImpl的setView函数向WMS服务添加一个窗口对象过程:</p>
<p> 1 )         requestLayout()在应用程序进程中进行窗口UI布局;</p>
<p> 2 )         WindowSession.add()向WMS服务注册一个窗口对象;</p>
<p> 3 )         注册应用程序进程端的消息接收通道;</p>
<h4>窗口UI布局过程</h4>
<p><img src= "http://www.2cto.com/uploadfile/Collfiles/20140702/2014070208183440.jpg" width= "707" height= "463" alt= "\" style=" width: 630px; height: 418 .751486325803px;"></p>
<p>framewZ喎� "http://www.2cto.com/kf/ware/vc/" target= "_blank" class = "keylink" >vcmtzXGJhc2VcY29yZVxqYXZhXGFuZHJvaWRcdmlld1xWaWV3Um9vdEltcGwuamF2YTwvcD4KPHByZSBjbGFzcz0= "brush:java;" > public void requestLayout() {
     //检查当前线程是否是UI线程
     checkThread();
     //标识当前正在请求UI布局
     mLayoutRequested = true ;
     scheduleTraversals();
}
</p></count;>

窗口布局过程必须在UI线程中进行,因此该函数首先检查调用requestLayout()函数的线程是否为创建ViewRootImpl对象的线程。然后调用scheduleTraversals()函数启动Choreographer的Callback遍历过程。

?
1
2
3
4
5
6
7
8
9
10
11
12
void scheduleTraversals() {
     if (!mTraversalScheduled) {
         mTraversalScheduled = true ;
         //暂停UI线程消息队列对同步消息的处理
         mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
         //向Choreographer注册一个类型为CALLBACK_TRAVERSAL的回调,用于处理UI绘制
         mChoreographer.postCallback(
                 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null );
         //向Choreographer注册一个类型为CALLBACK_INPUT的回调,用于处理输入事件
         scheduleConsumeBatchedInput();
     }
}

关于Choreographer的postCallback()用法在前面进行了详细的介绍,当Vsync事件到来时,mTraversalRunnable对象的run()函数将被调用。

frameworks\base\core\java\android\view\ViewRootImpl.java

?
1
2
3
4
5
6
7
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
final class TraversalRunnable implements Runnable {
         @Override
         public void run() {
             doTraversal();
         }
}

mTraversalRunnable对象的类型为TraversalRunnable,该类实现了Runnable接口,在其run()函数中调用了doTraversal()函数来完成窗口布局。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void doTraversal() {
     if (mTraversalScheduled) {
         mTraversalScheduled = false ;
         mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
         if (mProfile) {
             Debug.startMethodTracing( "ViewAncestor" );
         }
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals" );
         try {
             performTraversals();
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
         if (mProfile) {
             Debug.stopMethodTracing();
             mProfile = false ;
         }
     }
}


猜你喜欢

转载自blog.csdn.net/linghu_java/article/details/42964641