Android应用开发之Activity的渲染机制
白羽 2019-01-03 来源 :网络 阅读 1207 评论 0

摘要:本文将带你了解Android应用开发andriod开发之Activity的渲染机制,希望本文对大家学Android有所帮助。

    本文将带你了解Android应用开发andriod开发之Activity的渲染机制,希望本文对大家学Android有所帮助。


             

一切从setContentView说起。安卓中最常用的代码可能就是setContentView了,但大家有没有想过这个方法的背后到底做了些什么?


   

public class MainActivity extends Activity {

 @Override

 protected void onCreate(Bundle   savedInstanceState) {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

 }

}

   

直接跳转到Activity的源码我们可以看到,Activity.setContentView实际上调用了PhoneWindow.setContentView:


   

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) {

  ...

  mWindow = new   PhoneWindow(this, window);

  ...

}

 

public Window getWindow() {

 return mWindow;

}

 

public void setContentView(@LayoutRes int layoutResID) {

 getWindow().setContentView(layoutResID);

 initWindowDecorActionBar();

}

   

我们继续跟踪PhoneWindow的源码,可以发现最终layoutResID被inflate出来之后是成为了mDecor这个DecorView的子view。而DecorView实际上是一个FrameLayout:


   

public   void setContentView(int layoutResID) {

  if (mContentParent == null)   {

   installDecor();

  } else {

   mContentParent.removeAllViews();

  }

  mLayoutInflater.inflate(layoutResID, mContentParent);

  final Callback   cb = getCallback();

  if (cb   != null   && !isDestroyed())   {

   cb.onContentChanged();

  }

}

 

private void installDecor() {

  if (mDecor == null)   {

   mDecor =   generateDecor();

   ...

  }

  if (mContentParent == null)   {

   //mContentParent   实际上是mDecor的一个子view

   mContentParent =   generateLayout(mDecor);

   ...

  }

  ...

}

 

protected DecorView generateDecor() {

  return new DecorView(getContext(), -1);

}

 

private   final class DecorView extends FrameLayout implements RootViewSurfaceTaker   {

  ...

}

   

这里的generateLayout比较重要,它实际上是根据window的各种属性inflate出不同的layout挂到DecorView下面,而mContentParent是这个layout中的一个子ViewGroup。如果我们没有对window的属性进行设置就会使用默认的com.android.internal.R.layout.screen_simple这个layout:


protected ViewGroup generateLayout(DecorView decor) {  

  ...

  if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) !=   0) {

   ...

   layoutResource = com.android.internal.R.layout.screen_title_icons;

   ...

  } else   if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) !=   0

 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {

   layoutResource =   com.android.internal.R.layout.screen_progress;

  } else   if ((features & (1 << FEATURE_CUSTOM_TITLE)) !=   0) {

   ...

   layoutResource =   com.android.internal.R.layout.screen_custom_title;

   ...

  } ... else{

   layoutResource =   com.android.internal.R.layout.screen_simple;

  }

  ...

  View in = mLayoutInflater.inflate(layoutResource,   null);

  decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT,   MATCH_PARENT));

  ViewGroup contentParent =   (ViewGroup)findViewById(ID_ANDROID_CONTENT);

  ...

  return contentParent;

}

   

我们可以在AndroidSdk根目录/platforms/android-19/data/res/layout/下面找到这些layout   xml,例如screen_simple,这是个竖直的LinearLayout,由上方的ActionBar和下方的content   FrameLayout组成。它就是我们最常见的带ActionBar的activity样式:

 

<LinearLayout xmlns:android="//schemas.android.com/apk/res/android"

 android:layout_width="match_parent"

 android:layout_height="match_parent"

 android:fitsSystemWindows="true"

 android:orientation="vertical">

 <ViewStub android:id="@+id/action_mode_bar_stub"

 android:inflatedId="@+id/action_mode_bar"

 android:layout="@layout/action_mode_bar"

 android:layout_width="match_parent"

 android:layout_height="wrap_content"   />

 <FrameLayout

 android:id="@android:id/content"

 android:layout_width="match_parent"

 android:layout_height="match_parent"

 android:foregroundInsidePadding="false"

 android:foregroundGravity="fill_horizontal|top"

 android:foreground="?android:attr/windowContentOverlay"   />

</LinearLayout>

   

我们可以用一张图片来总结下Activity是如何管理布局的(这里假设DecorView里面添加了screen_simple这个布局):

 

Activity的布局是怎样被系统渲染的

在上一节中我们已经知道了Activity是怎样管理布局的。接着我们来看看Activity中的布局是如何渲染到系统的。

ActivityThread用于管理Activity的声明周期,之后我会专门写一篇文章来讲它。我们直接看ActivityThread.handleResumeActivity方法:


   

final   void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume)   {

 ...

 //performResumeActivity方法会调用Activity.onResume

 ActivityClientRecord r = performResumeActivity(token,   clearHide);

 ...

 r.window = r.activity.getWindow();

 View decor = r.window.getDecorView();

 decor.setVisibility(View.INVISIBLE);

 ViewManager wm =   a.getWindowManager();

 WindowManager.LayoutParams l =   r.window.getAttributes();

 a.mDecor = decor;

 l.type =   WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

 l.softInputMode |= forwardBit;

 if (a.mVisibleFromClient) {

 a.mWindowAdded = true;

 wm.addView(decor, l);

 }

 ...

}

   

可以看到它在Activity.onResume之后从Activity中获取了Window,然后又从window中获取了DecorView。最后使用WindowManager.addView将DecorView添加到了WindowManager中。这样就将DecorView在手机上渲染了出来。

WindowManager.addView方法可以将一个view渲染到手机界面上。不知道大家有没有做过类似悬浮球的应用,就是用WindowManager.addView去实现的。这里就不再展开了,大家有兴趣的话可以自己去搜索一下。

为什么不能在子线程中操作view

我们都知道,在安卓中必须在ui线程中操作ui,不能在子线程中对view进行操作,否则或抛出CalledFromWrongThreadException异常。但是在子线程中操作view是不是真的就一定会出现异常呢?让我们运行下面的代码:


   

public class MainActivity extends Activity {

 @Override

 protected void onCreate(Bundle savedInstanceState)   {

  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  new Thread(new Runnable() {

   @Override

   public void run() {

    ((TextView)findViewById(R.id.textView)).setText("子线程中操作view");

<div   class="line number    

   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!


本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程