最近在学习Android Framework的知识,写写博客记录一下学习的历程。学习中的代码基于Android Q。
我们大多数人刚开始接触Android开发的时候,都是从Android的四大组件开始的,而在Android的四大组件中,又是以Activity为学习的起点。在Activity的生命周期中,我们知道最先执行的就是 onCreate方法,在这里我们设置了我们的第一个布局文件,那么我们回到这最初的地方,从上往下看,以Activity的 onCreate为入口,走向Android Framework。
在Android开发者文档中对Activity的介绍为 :Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作。 每个 Activity 都会获得一个用于绘制其用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕并浮动在其他窗口之上。
要创建 Activity,您必须创建 Activity 的子类(或使用其现有子类),其中两个最重要的回调方法是:onCreate(),onPause() 。
onCreate():
必须实现此方法。系统会在创建的 Activity 时调用此方法。应该在实现内初始化 Activity 的必需组件。 最重要的是,必须在此方法内调用setContentView(),以定义 Activity 用户界面的布局。
现在我们来看看在Activity onCreate()中setContentView()做了哪些操作
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
方法很简单就两行代码,initWindowDecorActionBar()此方法为初始化ActionBar先不做讨论,代码的第一行调用了 getWindow()的setContentView(layoutResID)。
987 /**
988 * Retrieve the current {@link android.view.Window} for the activity.
989 * This can be used to directly access parts of the Window API that
990 * are not available through Activity/Screen.
991 *
992 * @return Window The current window, or null if the activity is not
993 * visual.
994 */
995 public Window getWindow() {
996 return mWindow;
997 }
getWindow()返回的是一个mWindow。通过源码得知mWindow是一个PhoneWindow对象,它是抽象类Window的实例。
我们来看看抽象类Window的注释:
53
54 /**
55 * Abstract base class for a top-level window look and behavior policy. An
56 * instance of this class should be used as the top-level view added to the
57 * window manager. It provides standard UI policies such as a background, title
58 * area, default key processing, etc.
59 *
60 * The only existing implementation of this abstract class is
61 * android.view.PhoneWindow, which you should instantiate when needing a
62 * Window.
63 */
64 public abstract class Window {
顶层窗口外观和行为策略的抽象基类,提供了标准的UI策略,比如背景,标题区域等。它的唯一实现为PhoneWindow,我们应当把它放入window manager中。
回来看看mWindow的初始化:
7701 final void attach(Context context, ActivityThread aThread,
7702 Instrumentation instr, IBinder token, int ident,
7703 Application application, Intent intent, ActivityInfo info,
7704 CharSequence title, Activity parent, String id,
7705 NonConfigurationInstances lastNonConfigurationInstances,
7706 Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7707 Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
...
7712 mWindow = new PhoneWindow(this, window, activityConfigCallback);
7713 mWindow.setWindowControllerCallback(this);
7714 mWindow.setCallback(this);
7715 mWindow.setOnWindowDismissedCallback(this);
7716 mWindow.getLayoutInflater().setPrivateFactory(this);
7717 ...
7748 mWindow.setWindowManager(
7749 (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
7750 mToken, mComponent.flattenToString(),
7751 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
7752 if (mParent != null) {
7753 mWindow.setContainer(mParent.getWindow());
7754 }
7755 mWindowManager = mWindow.getWindowManager();
7762 }
在对mWindow实例化之后,mWindow创建了WindowManager
763 /**
764 * Set the window manager for use by this Window to, for example,
765 * display panels. This is not used for displaying the
766 * Window itself -- that must be done by the client.
767 *
768 * @param wm The window manager for adding new windows.
769 */
770 public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
771 boolean hardwareAccelerated) {
772 mAppToken = appToken;
773 mAppName = appName;
774 mHardwareAccelerated = hardwareAccelerated;
775 if (wm == null) {
776 wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
777 }
778 mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
779 }
74 public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
75 return new WindowManagerImpl(mContext, parentWindow);
76 }
WindowManagerImpl是WindowManager的实例,而WindowManager继承自ViewManager
在接口ViewManager中,只有3个方法
19 /** Interface to let you add and remove child views to an Activity. To get an instance
20 * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
21 */
22 public interface ViewManager
23 {
34 public void addView(View view, ViewGroup.LayoutParams params);
35 public void updateViewLayout(View view, ViewGroup.LayoutParams params);
36 public void removeView(View view);
37 }
这三个方法其实就是 WindowManager 对外提供的主要功能,即添加 View、更新 View 和删除 View。
现在我们有了PhoneWindow 和 WindowManagerImpl,接下来再来看看
PhoneWindow中的 setContentView()实际上做了3件事:
158 // This is the top-level view of the window, containing the window decor.
159 private DecorView mDecor;
165 // This is the view in which the window contents are placed. It is either
166 // mDecor itself, or a child of mDecor where the contents go.
167 ViewGroup mContentParent;
422 @Override
423 public void setContentView(int layoutResID) {
424 // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
425 // decor, when theme attributes and the like are crystalized. Do not check the feature
426 // before this happens.
427 if (mContentParent == null) {
428 //step1: 创建应用程序窗口视图对象
installDecor();
429 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
430 mContentParent.removeAllViews();
431 }
432
433 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
434 final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
435 getContext());
436 transitionTo(newScene);
437 } else {
438 //step2: 部署UI布局设置
mLayoutInflater.inflate(layoutResID, mContentParent);
439 }
440 mContentParent.requestApplyInsets();
441 final Callback cb = getCallback();
442 if (cb != null && !isDestroyed()) {
443 //step3: 通知Activity
cb.onContentChanged();
444 }
445 mContentParentExplicitlySet = true;
446 }
447
mContentParent 用来描述一个类型为DecorView的视图对象,或者这个类型为DecorView的视图对象的一个子视图对象,用作UI容器。当它的值等于null的时候,就说明正在处理的应用程序窗口的视图对象还没有创建。在这种情况下,就会调用成员函数installDecor来创建应用程序窗口视图对象。
2681 private void installDecor() {
2682 mForceDecorInstall = false;
2683 if (mDecor == null) {
2684 mDecor = generateDecor(-1);
2685 ...
2692 }
2693 if (mContentParent == null) {
2694 mContentParent = generateLayout(mDecor);
2696 ...
2814 }
2815 }
installDecor()最主要的操作其实是做了两件事
1.generateDecor()实际上是创建了一个DecorView对象
2315 protected DecorView generateDecor(int featureId) {
...
2333 return new DecorView(context, featureId, this, getAttributes());
2334 }
2.generateLayout()应用主题数据,并为mDecor创建Layout布局
protected ViewGroup generateLayout(DecorView decor) {
//应用主题数据
...
layoutResource = R.layout.screen_simple;
mDecor.startChanging();
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
layoutResource会有很多判断,这里取一个简单的布局,contentParent通过findViewById赋值,并返回给mContentParent。
254 /**
255 * The ID that the main layout in the XML layout file should have.
256 */
257 public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
24 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
25 android:layout_width="match_parent"
26 android:layout_height="match_parent"
27 android:fitsSystemWindows="true"
28 android:orientation="vertical">
29 <ViewStub android:id="@+id/action_mode_bar_stub"
30 android:inflatedId="@+id/action_mode_bar"
31 android:layout="@layout/action_mode_bar"
32 android:layout_width="match_parent"
33 android:layout_height="wrap_content"
34 android:theme="?attr/actionBarTheme" />
35 <FrameLayout
36 android:id="@android:id/content"
37 android:layout_width="match_parent"
38 android:layout_height="match_parent"
39 android:foregroundInsidePadding="false"
40 android:foregroundGravity="fill_horizontal|top"
41 android:foreground="?android:attr/windowContentOverlay" />
42 </LinearLayout>
通过以上代码可知mContentParent为mDeco中的一个子View,它为主体内容的显示。
实际上是将我们在Activity onCreate setContentView中创建的自定义布局传入mContentParent中。同时以上分析结果可知,这个自定义的布局其实就是mDecor中的一个ID为content的FrameLayout
这是一个定义在抽象类Window里面的一个回调接口定义如下:
当content View发生变化的时候,需要回调它
476 /**
477 * This hook is called whenever the content view of the screen changes
478 * (due to a call to
479 * {@link Window#setContentView(View, android.view.ViewGroup.LayoutParams)
480 * Window.setContentView} or
481 * {@link Window#addContentView(View, android.view.ViewGroup.LayoutParams)
482 * Window.addContentView}).
483 */
484 public void onContentChanged();
在Activity中实现了此方法:
final void attach(Context context, ActivityThread aThread,
7702 Instrumentation instr, IBinder token, int ident,
7703 Application application, Intent intent, ActivityInfo info,
7704 CharSequence title, Activity parent, String id,
7705 NonConfigurationInstances lastNonConfigurationInstances,
7706 Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7707 Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
...
7714 mWindow.setCallback(this);
...
7762 }
725 public class Activity extends ContextThemeWrapper
726 implements LayoutInflater.Factory2,
727 Window.Callback, KeyEvent.Callback,
728 OnCreateContextMenuListener, ComponentCallbacks2,
729 Window.OnWindowDismissedCallback, WindowControllerCallback,
730 AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
3811 public void onContentChanged() {
3812 }
3813
自此Activity onCreate()的setContentView()中的主要操作分析完成。
下面来开始我们的技术总结。
在Activity中的onResume()并没有实际对UI进行操作,所以我们往下看看onResume()是如何被启动的。
Android Q版本中的Activity启动过程和之前不一样,我会在其他的文章来详细分析,这里不做过多的赘述。
/** Transition the client through previously initialized state sequence. */
205 private void performLifecycleSequence(ActivityClientRecord r, IntArray path,
206 ClientTransaction transaction) {
...
215 switch (state) {
216 case ON_CREATE:
217 mTransactionHandler.handleLaunchActivity(r, mPendingActions,
218 null /* customIntent */);
219 break;
220 case ON_START:
221 mTransactionHandler.handleStartActivity(r, mPendingActions);
222 break;
223 case ON_RESUME:
224 mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */,
225 r.isForward, "LIFECYCLER_RESUME_ACTIVITY");
226 break;
...
247 }
248 }
249 }
我们从handleResumeActivity这个方法开始看。
4256 @Override
4257 public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
4258 String reason) {
...
4263
4264 // TODO Push resumeArgs into the activity for consideration
4265 final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
4277
4278 final Activity a = r.activity;
4284
...
4291 boolean willBeVisible = !a.mStartedActivity;
4292 if (!willBeVisible) {
4293 try {
4294 willBeVisible = ActivityTaskManager.getService().willActivityBeVisible(
4295 a.getActivityToken());
4296 } catch (RemoteException e) {
4297 throw e.rethrowFromSystemServer();
4298 }
4299 }
4300 if (r.window == null && !a.mFinished && willBeVisible) {
4301 r.window = r.activity.getWindow();
4302 View decor = r.window.getDecorView();
4303 decor.setVisibility(View.INVISIBLE);
4304 ViewManager wm = a.getWindowManager();
4305 WindowManager.LayoutParams l = r.window.getAttributes();
4306 a.mDecor = decor;
4307 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
...
4321 if (a.mVisibleFromClient) {
4322 if (!a.mWindowAdded) {
4323 a.mWindowAdded = true;
4324 wm.addView(decor, l);
4325 } else {
4330 a.onWindowAttributesChanged(l);
4331 }
4332 }
4333
4334 ...
4370
4371 r.activity.mVisibleFromServer = true;
4372 mNumVisibleActivities++;
4373 if (r.activity.mVisibleFromClient) {
4374 r.activity.makeVisible();
4375 }
4376 }
...
4382 }
ActivityThread类的成员函数performResumeActivity的返回值是一个ActivityClientRecord对象r,这个ActivityClientRecord对象的成员变量activity描述的就是正在激活的Activity组件a。
mStartedActivity用来描述一个Activity组件是否正在启动一个新的Activity组件,如果是的话,那么这个Activity组件的成员变量mStartedActivity的值就会等于true,表示在新的Activity组件的执行结果返回来之前,当前Activity组件要保持不可见的状态。因此,当Activity组件a的成员变量mStartedActivity的值等于true的时候,它接下来就是不可见的,否则的话,就是可见的。
一个Activity组件所使用的本地窗口管理器保存它的成员变量mWindowManager中,这可以通过Activity类的成员函数getWindowManager来获得。getWindowManager返回的是一个WindowManager对象。它的实现为WindowManagerImpl。
接下来就会继续调用前面所获得的一个LocalWindowManager对象的成员函数addView来为当前正在激活的Activity组件的应用程序窗口视图对象关联一个ViewRoot对象。
LocalWindowManager类的成员变量mWindowManager指向的是一个WindowManagerImpl对象,因此,LocalWindowManager类的成员函数addView接下来调用WindowManagerImpl类的成员函数addView来给参数view所描述的一个应用程序窗口视图对象关联一个ViewRoot对象。
WindowManagerImpl对addview的实现是借助mGlobal的addview来实现的。
59 private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
92 @Override
93 public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
94 applyDefaultToken(params);
95 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
96 }
WindowManagerGlobal的addview中的4个参数
view为 r.window.getDecorView();
params为r.window.getAttributes();
mParentWindow为之前activity函数attach的phonewindow
**mContext.getDisplay()**为一个Display对象
我们再来看看WindowManagerGlobal的addview实现
149 private final ArrayList<View> mViews = new ArrayList<View>();
150 @UnsupportedAppUsage
151 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
152 @UnsupportedAppUsage
153 private final ArrayList<WindowManager.LayoutParams> mParams =
154 new ArrayList<WindowManager.LayoutParams>();
309 public void addView(View view, ViewGroup.LayoutParams params,
310 Display display, Window parentWindow) {
311 ...
335 ViewRootImpl root;
336 View panelParentView = null;
337
338 synchronized (mLock) {
339 // Start watching for system property changes.
340 if (mSystemPropertyUpdater == null) {
341 mSystemPropertyUpdater = new Runnable() {
342 @Override public void run() {
343 synchronized (mLock) {
344 for (int i = mRoots.size() - 1; i >= 0; --i) {
345 mRoots.get(i).loadSystemProperties();
346 }
347 }
348 }
349 };
350 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
351 }
352
353 int index = findViewLocked(view, false);
354 if (index >= 0) {
355 if (mDyingViews.contains(view)) {
356 // Don't wait for MSG_DIE to make it's way through root's queue.
357 mRoots.get(index).doDie();
358 } else {
359 throw new IllegalStateException("View " + view
360 + " has already been added to the window manager.");
361 }
362 // The previous removeView() had not completed executing. Now it has.
363 }
364
365 // If this is a panel window, then find the window it is being
366 // attached to for future reference.
367 if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
368 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
369 final int count = mViews.size();
370 for (int i = 0; i < count; i++) {
371 if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
372 panelParentView = mViews.get(i);
373 }
374 }
375 }
376
377 root = new ViewRootImpl(view.getContext(), display);
378
379 view.setLayoutParams(wparams);
380
381 mViews.add(view);
382 mRoots.add(root);
383 mParams.add(wparams);
384
385 // do this last because it fires off messages to start doing things
386 try {
387 root.setView(view, wparams, panelParentView);
388 } catch (RuntimeException e) {
389 // BadTokenException or InvalidDisplayException, clean up.
390 if (index >= 0) {
391 removeViewLocked(index, true);
392 }
393 throw e;
394 }
395 }
396 }
一个View对象在与一个ViewRoot对象关联的同时,还会关联一个WindowManager.LayoutParams对象,这个WindowManager.LayoutParams对象是用来描述应用程序窗口视图的布局属性的。
WindowManagerGlobal类有三个成员变量mViews、mRoots和mParams,它们分别是类型为View、ViewRoot和WindowManager.LayoutParams的数组。这三个数组的大小是始终保持相等的。这样, 有关联关系的View对象、ViewRoot对象和WindowManager.LayoutParams对象就会分别保存在数组mViews、mRoots和mParams的相同位置上,也就是说,mViews[i]、mRoots[i]和mParams[i]所描述的View对象、ViewRoot对象和WindowManager.LayoutParams对象是具有关联关系的。因此,WindowManagerGlobal类的三个参数版本的成员函数addView在关联一个View对象、一个ViewRoot对象和一个WindowManager.LayoutParams对象的时候,只要分别将它们放在数组mViews、mRoots和mParams的相同位置上就可以了。
如果参数view所描述的一个View对象还没有被关联过一个ViewRoot对象,那么成员函数addView就会创建一个ViewRoot对象,并且将它与参数view和params分别描述的一个View对象和一个WindowManager.LayoutParams对象保存在数组mViews、mRoots和mParams的相同位置上。
注意,如果数组mViews、mRoots和mParams尚未创建,那么成员函数addView就会首先分别为它们创建一个大小为1的数组,以便可以用来分别保存所要关联的View对象、ViewRoot对象和WindowManager.LayoutParams对象。
另一方面,如果数组mViews、mRoots和mParams已经创建,那么成员函数addView就需要分别将它们的大小增加1,以便可以在它们的末尾位置上分别保存所要关联的View对象、ViewRoot对象和WindowManager.LayoutParams对象。
当一一绑定之后就开始调用root的setview
779 public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
780 synchronized (this) {
781 if (mView == null) {
782 mView = view;
870 ...
875 requestLayout();
876 ...
882 try {
...
886 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
887 getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
888 mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
889 mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
890 mTempInsets);
891 setFrame(mTmpFrame);
892 ...
905 }
906
907 ....
1013 }
1014 }
1015 }
viewroot在setView的时候会调用requestLayout方法,并且这里会和WMS进行跨进程通信,拿到屏幕的Rect
1461 @Override
1462 public void requestLayout() {
1463 if (!mHandlingLayoutInLayoutRequest) {
1464 if (ViewDebugManager.DEBUG_REQUESTLAYOUT) {
1465 Log.d(mTag, "requestLayout: mView = " + mView + ", this = " + this,
1466 new Throwable("requestLayout"));
1467 }
1468 checkThread();
1469 mLayoutRequested = true;
1470 scheduleTraversals();
1471 }
1472 }
requestLayout首先调用另外一个成员函数checkThread来检查当前线程是否就是创建当前正在处理的ViewRoot对象的线程。如果不是的话,那么ViewRoot类的成员函数checkThread就会抛出一个异常出来。
ViewRoot类的成员函数requestLayout首先将其成员变量mLayoutRequested的值设置为true,表示应用程序进程的UI线程正在被请求执行一个UI布局操作,接着再调用另外一个成员函数scheduleTraversals来继续执行UI布局的操作。
1743 void scheduleTraversals() {
...
1746 if (!mTraversalScheduled) {
1747 mTraversalScheduled = true;
1750 mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
1755 mChoreographer.postCallback(
1756 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
1757 if (!mUnbufferedInputDispatch) {
1758 scheduleConsumeBatchedInput();
1759 }
1760 notifyRendererOfFramePending();
1765 }
mTraversalScheduled用来表示应用程序进程的UI线程是否已正在处理
通过mChoreographer.postCallback最终会调到performTraversals方法来处理
7864 final class TraversalRunnable implements Runnable {
7865 @Override
7866 public void run() {
7867 doTraversal();
7868 }
7869 }
7870 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
1776 void doTraversal() {
1777 ...
1781
1782 if (mTraversalScheduled) {
1783 mTraversalScheduled = false;
1784 mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
1785
1786 ...
1791 performTraversals();
1793 ...
1797 }
1798 }
现在来以performTraversals()为起点,来分析View的整个绘制流程。
2019 private void performTraversals() {
...
2648 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
2705 performLayout(lp, mWidth, mHeight);
2706 ...
2878 performDraw();
2898 }
view的绘制过程在performTraversals中最主要的就是3个方法
performMeasure 测量、performLayout 布局、performDraw 绘制
performDraw主要调用了draw方法
}
3612
3613 private boolean draw(boolean fullRedrawNeeded) {
3614 Surface surface = mSurface;
3615 if (!surface.isValid()) {
3616 return false;
3617 }
...
3781
3782 if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,
3783 scalingRequired, dirty, surfaceInsets)) {
3787 return false;
3788 }
...
3796 return useAsyncReport;
3797 }
接着draw又会调用drawSoftware
*/
3802 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
3803 boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
3804
3805 // Draw with software renderer.
3806 final Canvas canvas;
3807
3827 canvas = mSurface.lockCanvas(dirty);
3828 ...
3833 canvas.setDensity(mDensity);
3834 ...
3877 canvas.translate(-xoff, -yoff);
3878 if (mTranslator != null) {
3879 mTranslator.translateCanvas(canvas);
3880 }
3881 canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
3882
3883 mView.draw(canvas);
3884
3885 drawAccessibilityFocusedDrawableIfNeeded(canvas);
3886
3890 try {
3891 surface.unlockCanvasAndPost(canvas);
3892 } catch (IllegalArgumentException e) {
3893 Log.e(mTag, "Could not unlock surface, surface = " + surface
3894 + ", canvas = " + canvas + ", this = " + this, e);
3895 mLayoutRequested = true; // ask wm for a new surface next time.
3896 //noinspection ReturnInsideFinallyBlock
3897 return false;
3898 }
3899
3904 return true;
3905 }
3906
drawSoftware最终会调用view的draw