源码分析篇-Android绘制流程(一)窗口启动流程分析

更新时间:2023-07-17 13:48:26 阅读: 评论:0

源码分析篇-Android绘制流程(⼀)窗⼝启动流程分析
Activity、View、Window之间的关系可以⽤以下的简要UML关系图表⽰,在这⾥贴出来,⽐较能够帮组后⾯流程分析部分的阅读。
⼀、Activity的启动流程
  在startActivity()后,经过⼀些逻辑流程会通知到ActivityManagerService(后⾯以AMS简称),AMS接收到启动acitivty的请求后,会通过跨进程通信调⽤AcitivtyThread.handleLauncherActivity()⽅法,我们从这⾥开始分析,⾸先来看handleLauncherActivity()⽅法。
   private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...// Initialize before creating the activity怎么去掉法令纹
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
      if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        //该⽅法会调⽤到Activity的onResume()⽅法
        ken, fal, r.isForward,
              !r.activity.mFinished && !r.startsNotResumed, r.lastProcesdSeq, reason);
        ...
      }
...
}
  这⾥重点关注三个⽅法(加粗的地⽅),⾸先来看WindowManagerGlobal.initialize(),WindowManagerGlobal是单例模式的,⼀个进
程内只有⼀个,这⾥调⽤该类的初始化⽅法,后续我们再对该类的作⽤和相关⽅法进⾏分析;第三个是在创建好Activity后调⽤Acitivty的onResume()⽅法。这⾥我们来看需关注的第⼆个⽅法performLaunchActivity(),代码如下。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
      ...
     //通过反射⽅式创建Activity
Activity activity = null;
try {
java.lang.ClassLoader cl = ClassLoader();
activity = wActivity(
cl, ClassName(), r.intent);
StrictMode.Class());
r.intent.tExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.tClassLoader(cl);
}
} catch (Exception e) {
if (!Exception(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
鹌鹑养殖+ ": " + e.toString(), e);
}
}
try {
.
..
       if (activity != null) {
Context appContext = createBaContextForActivity(r, activity);
CharSequence title = r.activityInfo.PackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
觉多音字}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPrerveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
          ...
          //调⽤acitivity的onCreate()⽅法
           if (r.isPersistable()) {
               mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
           } el {
               mInstrumentation.callActivityOnCreate(activity, r.state);
           }
          ...
       }
return activity;
}
  这个⽅法主要是读取Acitivity这⾥利⽤反射创建出ActivityClientRecord所要求的Activity对象,然后调⽤了acitivity.attach()⽅法。注意attach()传⼊的参数有很多,在performLacunchActivity()⽅法流程中,调⽤attach()⽅前,我们省略掉的步骤基本都在为这些参数做准
备,attach()⽅法的作⽤其实就是将这些参数配置到新创建的Activity对象中;⽽在attach之后则会回调到acitivity的onCreate()⽅法。我们进⼊Activity.java类详细来看下attach⽅法。
  此外,在attach之前会初始化⼀个Window对象,Window.java是⼀个抽象类,代表了⼀个矩形不可见的容器,主要负责加载显⽰界⾯,每个Activity都会对应了⼀个Window对象。如果ActivityClientRecord.mPendingRevomeWindow变量中已经保存了⼀个Window对象,则会在后⾯的attach⽅法中被使⽤,具体使⽤的场景会在后⾯中介绍。
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window) {
attachBaContext(context);
mFragments.attachHost(null/*parent*/);
mWindow = new PhoneWindow(this, window);//(1)
mWindow.tWindowControllerCallback(this);
mWindow.tCallback(this);
mWindow.tOnWindowDismisdCallback(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.tSoftInputMode(info.softInputMode);
四级题
}
if (info.uiOptions != 0) {
mWindow.tUiOptions(info.uiOptions);
}
     ... //初始化Acitity相关属性
mWindow.tWindowManager(
(SystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//(2)
if (mParent != null) {
mWindow.Window());
}
mWindowManager = WindowManager();
mCurrentConfig = config;
}
  重点关注初始化window对象的操作,⾸先创建了PhoneWindow对象为activity的mWindow变量,在创建时传⼊了上⼀个activity对应的window对象,之后⼜将这个acitivity设置为window对象的回调。Activity中很多操作view相关的⽅法,例如tContentView()、findViewById()、getLayoutInflater()等,实际上都是直接调⽤到PhoneWindow⾥⾯的相关⽅法。创建完acitivty对应的PhoneWindow之后便会调⽤tWindowManager()⽅法。⾸先来看PhonewWindow构造⽅法。
  public PhoneWindow(Context context, Window prervedWindow) {
this(context);
// Only main activity windows u decor context, all the other windows depend on whatever
// context that was given to them.
mUDecorContext = true;if (prervedWindow != null) { //快速重启activity机制
幸福成长mDecor = (DecorView) DecorView();
日本经营四圣
mElevation = Elevation();
mLoadElevation = fal;
mForceDecorInstall = true;
// If we're prerving window, carry over the app token from the prerved
// window, as we'll be skipping the addView in handleResumeActivity(), and
// the token will not be updated as for a new window.
getAttributes().token = Attributes().token;
}
// Even though the device doesn't support picture-in-picture mode,
// an ur can force using it through developer options.
boolean forceResizable = ContentResolver(),
DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
mSupportsPictureInPicture = forceResizable || PackageManager().hasSystemFeature(
PackageManager.FEATURE_PICTURE_IN_PICTURE);
}
  ⾸先要关注的就是prerviedWindow参数,这个参数就是上⼀段中提到的mPendingRevomeWindow变量,这个参数在什么时候会不为空呢?其实这⾥的逻辑是⽤来快速重启acitivity的,⽐如你的⼀个activity已经启动了,但是主题换了或者configuration变了,这⾥只需要重新加载资源和view,没必重新再执⾏DecorView的创建⼯作。
  另⼀个要关注的就是mDecor变量,这个变量是DecorView类型的,如果这⾥没有初始化的话,则会在调⽤tContentView⽅法中new ⼀个DecorView对象出来。DecorView对象继承⾃FrameLayout,所以他本质上还是⼀个view,只是对FrameLayout做了⼀定的包装,例如添加了⼀些与window需要调⽤的⽅法tWindowBackground()、tWindowFrame()等。我们知道,acitivty界⾯的view是呈树状结构的,⽽mDecor变量在这⾥作为activity的界⾯的根view存在。这三个点关系就⽐如,PhoneWindow是⼀块⼿机电⼦屏,DecorView就是电⼦屏要显⽰的内容,Activity就是⼿机电⼦屏安装位置。
  再来看创建PhonewWindow之后调⽤的tWindowManager()⽅法的逻辑,这段代码是在PhonewWindow.java的⽗类Window.java中代码如下。
public void tWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| Boolean(PROPERTY_HARDWARE_UI, fal);
if (wm == null) {
wm = (SystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
  对于wWindowManager变量,实际上这⾥是创建了⼀个WindowManagerImpl对象。⾸先是这种⾸先获取系统服务的代理到wm上,然后强制转换为WindowManagerImpl调⽤createLocalWindowManager(),在createLocalWindowManager()实际是执⾏了⼀个new WindowManagerImpl()到⽅法来创建。关于这部分代码看了很久很困惑的⼀个点,就是为啥要弄个这么复杂的逻辑,直接把上⾯加粗的代码改为new WindowManagerImpl(...),这养会有什么区别吗?如果有⼤虾看到这⾥,希望能帮我解答。
  在WindowManager中保存了对于单例对象WindowManagerGloble的引⽤,即mGlobal变量。此外,WindowManager.java实现了WindowManager⼜,⽽WindowManager继承⾃ViewManager接⼝,ViewManager接⼝⽅法如下⽅代码。
public interface ViewManager
{
/**
* Assign the pasd LayoutParams to the pasd View and add the view to the window.
* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
* errors, such as adding a cond view to a window without removing the first view.
* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
* condary {@link Display} and the specified display can't be found
* (e {@link android.app.Prentation}).
* @param view The view to be added to this window.
* @param params The LayoutParams to assign to view.
*/
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
  在WindowManager对于addView()、updateViewLayout()和removeView()的实现,都是调⽤到mGlobal变量对应的addView()、updateViewLayout()和removeView()⽅法来实现的。这⾥我们
这样我们分析完activity以及对应的window对象的创建,回到performLauncerActivity()⽅法中Activity a = performLaunchActivity(r, customIntent)这⼀步骤,之后便回调activity⽅法的onCreate(),在onCreate()的tContentView⽅法会初始化DecorView,并根据传⼊参数加载布局,详细步骤在下⼀节介绍。
  再回到最初的handlerLaunchActivity()⽅法中,通过调⽤performLauncerActivity()创建出⼀个Acitivty对象后,如果创建成功则执⾏handleResumeActivity(),便执⾏到了Acitivity的onResume()⽅法,即是完成了acitivty的启动。
⼆、tContentView()流程
  ⾸先,我们⼀般在onCreate()⾥调⽤tContentView()的⽅法。
@override
protected void onCreate(Bundle savedInstanceState) {
  Create(savedInstanceState);
  tContentView(R.layout.activity_main);
}
  这⾥实际调⽤到到地⽅是Acitivity.java类中的tContentView()⽅法,如下。
public void tContentView(@LayoutRes int layoutResID) {
  getWindow().tContentView(layoutResID);
  initWindowDecorActionBar();
}
  这⾥getWindow()返回的是Acitivity.java类中的mWindow变量,就是Activity创建时⼀起创建的PhoneWindow对象,进⼊到
@Override
public void tContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} el if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { //过渡动画机制相关
final Scene newScene = SceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} el {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
}
mContentParentExplicitlySet = true;
}
  代码⾥涉及到FEATURE_CONTENT_TRANSITIONS的属性,这⾥是Android的过渡动画相关机制,这⾥我们不再展开详述。⼀般的Acitivty启动时,会进⼊mContentParent为null的逻辑,⾸先调⽤的是installDecor()⽅法,完成DecorView的创建⼯作;之后调⽤mLayoutInflater.inflate()⽅法将我们传⼊的资源⽂件转换为view树,装载到mContentParent中。⾸先来看installDecor()代码。
private void installDecor() {
mForceDecorInstall = fal;
if (mDecor == null) { //创建DecorView
mDecor = generateDecor(-1);
mDecor.tDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.tIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} el {
mDecor.tWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
  在这个⽅法⼜两个主要步骤,⾸先是使⽤generateDecor()⽅法创建了DecorView对象,generateDecor()⽅法⽐较简单,主要就是执⾏new DecorView(context, featureId, this, getAttributes())⽅法,这⾥不再贴出代码;重点来看generateLayout()⽅法,这个⽅法⽣成的mContentParent是作为来我们后续加载加载的⽤户的布局的⽗布局存在的。
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
     //获取当前主题的相关属性
TypedArray a = getWindowStyle();
...  //⼀⼤段的根据获取到到主题属性,解析保存到PhonwWindow的相关参数的变量中
int layoutResource;
int features = getLocalFeatures();
     ... //⼀⼤段根据PhoneWindow的设定好的属性(features和mIsFloating)的判断,为layoutResource进⾏赋值,
//值可以为R.layout.screen_custom_title、R.layout.screen_action_bar等
mDecor.startChanging();
     //将layoutRsourece值对应的布局⽂件加载到DecorView中
     //在加载给DecorView的布局⽂件中有⼀块id为ID_ANDROID_CONTENT的区域是⽤于⽤户显⽰⾃⼰布局的,也是tContextView传⼊的布局显⽰的地⽅
     //这块区域会以ViewGroup的形式赋值给mContentParent变量,这个ViewGroup即是⽤户布局的⽗布局节点
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
     ... //继续⼀⼤段的属性配置
mDecor.finishChanging();
return contentParent;
}
  generateLayout⽅法实际就是解析出主题的相关属性,根据不同的主题样式的属性值选择不同的布局⽂件设置到DecorView中(DecorView本事就是FrameLayout)。在view的树状结构下,DecorView即是整个Window显⽰的视图的根节点,在DecorView的⼦节点中⼜有⼀块id为ID_ANDROID_CONTENT的区域有⼀块区域作为mContentParent变量⽤于加载⽤户的布局,与mContentParent平级的视图有ActionBar视图和Title的视图。总结来说,installDecor()⽅法实质就是产⽣mDecor和mContentParent对象。在installDecor之后,会执⾏到mLayoutInflater.inflate(layoutResID, mContentParent)⽅法将⽤户传⼊的布局转化为view再加⼊到mC
ontentParent上。这样就完成了tContentView()流程。
三、handleResumeActivity()流程
  在⽂章开头贴出的第⼀段AcitityThread.handleLauncherActivity()⽅法的代码中,执⾏完performLaunchAcitity()创建好Acitivity后,便会执⾏到handleResumeActivity()⽅法,该⽅法代码如下。
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int q, String reason) {
...// TODO Push resumeArgs into the activity for consideration
李瑞洵// 该⽅法执⾏过程中会调⽤到Acitity的onResume()⽅法,返回的ActivityClientRecord对象描述的即是创建好的Activity
     r = performResumeActivity(token, clearHide, reason);
if (r != null) {
final Activity a = r.activity;//返回之前创建的Acitivty
苏东坡的词
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow

本文发布于:2023-07-17 13:48:26,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1085124.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:对象   创建   变量   布局
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图