前言

最近在学习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 用户界面的布局。

setContentView()

现在我们来看看在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 that990       * are not available through Activity/Screen.991       *992       * @return Window The current window, or null if the activity is not993       *         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.  An56   * instance of this class should be used as the top-level view added to the57   * window manager. It provides standard UI policies such as a background, title58   * area, default key processing, etc.59   *60   * 

The only existing implementation of this abstract class is61 * android.view.PhoneWindow, which you should instantiate when needing a62 * Window.63 */64 public abstract class Window {

顶层窗口外观和行为策略的抽象基类,提供了标准的UI策略,比如背景,标题区域等。它的唯一实现为PhoneWindow,我们应当把它放入window manager中。

mWindow的创建

回来看看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 the766       * 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 instance20    * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.21    */22  public interface ViewManager23  {     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。
现在我们有了PhoneWindowWindowManagerImpl,接下来再来看看

PhoneWindow中的 setContentView()

PhoneWindow中的 setContentView()实际上做了3件事:

  • 调用成员函数installDecor来创建应用程序窗口视图对象
  • 调用LayoutInflater对象的成员函数inflate来将参数layoutResID所描述的一个UI布局设置到前面所创建的应用程序窗口视图中
  • 调用一个Callback接口的成员函数onContentChanged来通知对应的Activity组件,它的视图内容发生改变了
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 either166      // mDecor itself, or a child of mDecor where the contents go.167      ViewGroup mContentParent;422      @Override423      public void setContentView(int layoutResID) {     424          // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window425          // decor, when theme attributes and the like are crystalized. Do not check the feature426          // 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来创建应用程序窗口视图对象。

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()最主要的操作其实是做了两件事

  • 创建 一个名为mDecor的DecorView对象
  • 应用当前主题的数据,并为mDecor创建Layout布局

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     <FrameLayout36          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,它为主体内容的显示。

mLayoutInflater.inflate(layoutResID, mContentParent);

实际上是将我们在Activity onCreate setContentView中创建的自定义布局传入mContentParent中。同时以上分析结果可知,这个自定义的布局其实就是mDecor中的一个ID为content的FrameLayout

onContentChanged

这是一个定义在抽象类Window里面的一个回调接口定义如下:
当content View发生变化的时候,需要回调它

476          /**477           * This hook is called whenever the content view of the screen changes478           * (due to a call to479           * {@link Window#setContentView(View, android.view.ViewGroup.LayoutParams)480           * Window.setContentView} or481           * {@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 ContextThemeWrapper726          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()中的主要操作分析完成。
下面来开始我们的技术总结。

  1. Activity中setContentView()实际上是调用的Window的setContentView(),而PhoneWindow是Window的唯一实例,具体实现了setContentView()
  2. PhoneWindow自己并不是一个视图(View),它的成员变量mDecor才是整个界面的视图,mDecor是在generateDecor()中被创建,generateLayout()的时候被填充出来的
  3. mContentParent是通过findViewById()直接从mDecor中获取出来的,而mContentParent实际上是用户自定义布局的主体内容

最后上一张图来描述他们的关系。

onResume()的执行

在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      @Override4257      public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,4258              String reason) {                   ...4263  4264          // TODO Push resumeArgs into the activity for consideration4265          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      @Override93      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个参数
viewr.window.getDecorView();
paramsr.window.getAttributes();
mParentWindow为之前activity函数attach的phonewindow
**mContext.getDisplay()**为一个Display对象
我们再来看看WindowManagerGlobal的addview实现

149      private final ArrayList<View> mViews = new ArrayList<View>();150      @UnsupportedAppUsage151      private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();152      @UnsupportedAppUsage153      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 " + view360                              + " 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 being366              // 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 things386              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      @Override1462      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          @Override7866          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 = " + surface3894                          + ", canvas = " + canvas + ", this = " + this, e);3895                  mLayoutRequested = true;    // ask wm for a new surface next time.3896                  //noinspection ReturnInsideFinallyBlock3897                  return false;3898              }3899  3904          return true;3905      }3906  

drawSoftware最终会调用view的draw

更多相关文章

  1. 箭头函数的基础使用
  2. 类和 Json对象
  3. Python技巧匿名函数、回调函数和高阶函数
  4. Android通过USB与PC通信
  5. Android之AIDL实现两个app的调用以及双进程app的进程通信
  6. 阿里android面试准备与题目整理
  7. Android的init过程详解(一)
  8. Android日志系统Logcat源代码简要分析
  9. Android中如何修改编译的资源ID值(默认值是0x7F...可以随意改成0

随机推荐

  1. 编译Android版本TensorFlow
  2. android 触摸事件传递机制
  3. [置顶] 让你的Android应用与外部元素互动
  4. Android之通知使用权
  5. android 实现GridView多选效果
  6. Android(安卓)中 控制 wifi
  7. Android(安卓)3.0 honeycomb TextView on
  8. openCv CameraBridgeViewBase 竖屏显示对
  9. 关于SQLite数据库的那些事儿
  10. 命令行执行Android程序