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

来源:互联网 发布:wildcard ssl nginx 编辑:程序博客网 时间:2024/05/18 00:12

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
finalvoid handleResumeActivity(IBinder token, booleanclearHide, booleanisForward) {
    unscheduleGcIdler();
    ActivityClientRecord r;
    try{
        ①r = performResumeActivity(token, clearHide);
    }catch(Exception e) {
        ...
    }
    if(r != null) {
        finalActivity 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);
            }
        }elseif (!willBeVisible) {
            ...
        }
        ...
        if(!r.onlyLocalRequest) {
            r.nextIdle = mNewActivities;
            mNewActivities = r;
            Looper.myQueue().addIdleHandler(newIdler());
        }
        ...
    }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
publicfinal 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
publicvoid addView(View view, android.view.ViewGroup.LayoutParams params) {
    mWindowManager.addView(view, params, mCompatibilityInfo);
}

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

?
1
2
3
publicvoid 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
privatevoid addView(View view, ViewGroup.LayoutParams params,
        CompatibilityInfoHolder cih, booleannest) {
    ...
    finalWindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
    ViewRootImpl root;
    View panelParentView = null;
    synchronized(this) {
        ...
        //从mViews中查找当前添加的View
        intindex = findViewLocked(view, false);
        //如果已经存在,直接返回
        if(index >= 0) {
            ...
            return;
        }
        //尚未添加当前View
        if(wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            finalint count = mViews != null? mViews.length : 0;
            for(inti=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>
<preclass="brush:java;">publicViewRootImpl(Context context) {
    ...
    ①getWindowSession(context.getMainLooper());
    mThread = Thread.currentThread();
    mLocation = newWindowLeaked(null);
    mLocation.fillInStackTrace();
    mWidth = -1;
    mHeight = -1;
    mDirty = newRect();
    mTempRect = newRect();
    mVisRect = newRect();
    mWinFrame = newRect();
    ②mWindow = newW(this);
    mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    mInputMethodCallback = newInputMethodCallback(this);
    mViewVisibility = View.GONE;
    mTransparentRegion = newRegion();
    mPreviousTransparentRegion = newRegion();
    mFirst = true;// true for the first time the view is added
    mAdded = false;
    mAccessibilityManager = AccessibilityManager.getInstance(context);
    mAccessibilityInteractionConnectionManager =
        newAccessibilityInteractionConnectionManager();
    mAccessibilityManager.addAccessibilityStateChangeListener(
            mAccessibilityInteractionConnectionManager);
    ③mAttachInfo = newView.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>
<preclass="brush:java;">privatefinal Surface mSurface = newSurface();
finalViewRootHandler mHandler = newViewRootHandler();
</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>
<preclass="brush:java;">publicstatic 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());
                floatanimatorScale = windowManager.getAnimationScale(2);
                ValueAnimator.setDurationScale(animatorScale);
                mInitialized = true;
            }catch(RemoteException e) {
            }
        }
        returnsWindowSession;
    }
}
</pre>
<p>以上函数通过WMS的openSession函数创建应用程序与WMS之间的连接通道,即获取IWindowSession代理对象,并将该代理对象保存到ViewRootImpl的静态成员变量sWindowSession中</p>
<preclass="brush:java;">staticIWindowSession sWindowSession;</pre>
<p>因此在应用程序进程中有且只有一个IWindowSession代理对象。</p>
<p>frameworks\base\services\java\com\android\server\wm\WindowManagerService.java</p>
<preclass="brush:java;">publicIWindowSession openSession(IInputMethodClient client,
        IInputContext inputContext) {
    if(client == null)thrownew IllegalArgumentException("null client");
    if(inputContext == null)thrownew IllegalArgumentException("null inputContext");
    Session session = newSession(this, client, inputContext);
    returnsession;
}
</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>
<preclass="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>
<preclass="brush:java;">publicstatic Choreographer getInstance() {
    returnsThreadInstance.get();
}
</pre><preclass="brush:java;">privatestatic final ThreadLocal<choreographer> sThreadInstance =
        newThreadLocal<choreographer>() {
    @Override
    protectedChoreographer initialValue() {
        Looper looper = Looper.myLooper();
        if(looper == null) {
            thrownew IllegalStateException("The current thread must have a looper!");
        }
        returnnew Choreographer(looper);
    }
};
</choreographer></choreographer></pre>
<p>为调用线程创建一个Choreographer实例,调用线程必须具备消息循环功能,因为ViewRootImpl对象的构造是在应用程序进程的UI主线程中执行的,因此创建的Choreographer对象将使用UI线程消息队列。</p>
<preclass="brush:java;">privateChoreographer(Looper looper) {
    mLooper = looper;
    //创建消息处理Handler
    mHandler = newFrameHandler(looper);
    //如果系统使用了Vsync机制,则注册一个FrameDisplayEventReceiver接收器
    mDisplayEventReceiver = USE_VSYNC ? newFrameDisplayEventReceiver(looper) : null;
    mLastFrameTimeNanos = Long.MIN_VALUE;
    //屏幕刷新周期
    mFrameIntervalNanos = (long)(1000000000/
            newDisplay(Display.DEFAULT_DISPLAY, null).getRefreshRate());
    //创建回调数组
    mCallbackQueues = newCallbackQueue[CALLBACK_LAST + 1];
    //初始化数组
    for(inti = 0; i <= CALLBACK_LAST; i++) {
        mCallbackQueues[i] = newCallbackQueue();
    }
}
</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>
<preclass="brush:java;">publicvoid postCallback(intcallbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}
</pre>
<p> </p>
<preclass="brush:java;">publicvoid postCallbackDelayed(intcallbackType,
        Runnable action, Object token, longdelayMillis) {
    if(action == null) {
        thrownew IllegalArgumentException("action must not be null");
    }
    if(callbackType < 0|| callbackType > CALLBACK_LAST) {
        thrownew IllegalArgumentException("callbackType is invalid");
    }
    postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
</pre>
<p> </p>
<preclass="brush:java;">privatevoid postCallbackDelayedInternal(intcallbackType,
        Object action, Object token, longdelayMillis) {
    synchronized(mLock) {
        finallong now = SystemClock.uptimeMillis();
        finallong 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>
<preclass="brush:java;">privatefinal class FrameHandler extendsHandler {
    @Override
    publicvoid handleMessage(Message msg) {
        switch(msg.what) {
            caseMSG_DO_SCHEDULE_CALLBACK:
                doScheduleCallback(msg.arg1);
                break;
        }
    }
}
</pre>
<p> </p>
<preclass="brush:java;">voiddoScheduleCallback(intcallbackType) {
    synchronized(mLock) {
        if(!mFrameScheduled) {
            finallong now = SystemClock.uptimeMillis();
            if(mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                scheduleFrameLocked(now);
            }
        }
    }
}
</pre>
<p> </p>
<preclass="brush:java;">privatevoid scheduleFrameLocked(longnow) {
    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机制,则使用异步消息延时执行屏幕刷新
            finallong 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>
<preclass="brush:java;">voiddoFrame(longframeTimeNanos, intframe) {
    finallong startNanos;
    synchronized(mLock) {
        if(!mFrameScheduled) {
            return;// no work to do
        }
        //保存起始时间
        startNanos = System.nanoTime();
        //由于Vsync事件处理采用的是异步方式,因此这里计算消息发送与函数调用开始之间所花费的时间
        finallong jitterNanos = startNanos - frameTimeNanos;
        //如果线程处理该消息的时间超过了屏幕刷新周期
        if(jitterNanos >= mFrameIntervalNanos) {
            //计算函数调用期间所错过的帧数
            finallong 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.");
            }
            finallong 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>
<preclass="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>
<preclass="brush:java;">voiddoCallbacks(intcallbackType, longframeTimeNanos) {
    CallbackRecord callbacks;
    synchronized(mLock) {
        finallong 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{
                finalCallbackRecord next = callbacks.next;
                recycleCallbackLocked(callbacks);
                callbacks = next;
            }while(callbacks != null);
        }
    }
}
</pre>
<p>该函数就是按时间顺序先后执行到时的CallbackRecord</p>
<preclass="brush:java;">privatestatic final class CallbackRecord {
    publicCallbackRecord next;
    publiclong dueTime;
    publicObject action; // Runnable or FrameCallback
    publicObject token;
 
    publicvoid run(longframeTimeNanos) {
        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>
<preclass="brush:java;">privatevoid scheduleVsyncLocked() {
    //申请Vsync信号
    mDisplayEventReceiver.scheduleVsync();
}</pre>
<p>FrameDisplayEventReceiver继承于DisplayEventReceiver类,Vsync请求在DisplayEventReceiver中实现。</p>
<p>frameworks\base\core\java\android\view\ DisplayEventReceiver.java </p>
<preclass="brush:java;">publicvoid 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>
<preclass="brush:java;">staticvoid 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>
<preclass="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);
            returnstatus;
        }
        mWaitingForVsync = true;
    }
    returnOK;
}
</pre>
<p align="left">VSync请求过程又转交给了DisplayEventReceiver</p>
<p>frameworks\native\libs\gui\ DisplayEventReceiver.cpp </p>
<preclass="brush:java;">status_t DisplayEventReceiver::requestNextVsync() {
    if(mEventConnection != NULL) {
        mEventConnection->requestNextVsync();
        returnNO_ERROR;
    }
    returnNO_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>
<preclass="brush:java;">publicvoid 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 instanceofRootViewSurfaceTaker) {
                mSurfaceHolderCallback =
                        ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                if(mSurfaceHolderCallback != null) {
                    mSurfaceHolder = newTakenSurfaceHolder();
                    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 = newInputChannel();
            }
            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 instanceofRootViewSurfaceTaker) {
                mInputQueueCallback =
                    ((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
            }
            if(mInputChannel != null) {
                if(mInputQueueCallback != null) {
                    mInputQueue = newInputQueue(mInputChannel);
                    mInputQueueCallback.onInputQueueCreated(mInputQueue);
                }else{
                    mInputEventReceiver = newWindowInputEventReceiver(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;">publicvoid 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
voidscheduleTraversals() {
    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
finalTraversalRunnable mTraversalRunnable = newTraversalRunnable();
finalclass TraversalRunnable implementsRunnable {
        @Override
        publicvoid 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
voiddoTraversal() {
    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;
        }
    }
}


0 0
原创粉丝点击