安卓Activity创建界面过程-API源码解析

本文深入探讨了Android中Activity如何创建界面的过程,通过API源码分析,揭示了从Activity的attach方法开始,如何经过PolicyManager的静态方法调用来构建界面。尽管源码路径复杂,但对理解Android系统的运行机制具有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道Android 软件每一个界面 都是Activity构成的   那么Activity  是怎么创建一个界面的呢   ?

接下来是看源码时间   过程复杂   耐心观看

setContentView(R.layout.activity_main);
这个大家再熟不过了     onCreate中调用这个就可以创建对应布局文件的界面 

接下来看API源码  :

activity中:

public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
getWindow()得到的是一个Window对象

public Window getWindow() {
        return mWindow;
    }

Window是一个抽象类  不可能创建对象   

那么我们找一下它的实现类       (Activity六千行代码   这是真难找啊  )。

在attach方法中:    

 //  attach 方法是Activity通过反射实例化之后调用的第一个方法 ,之后生命周期的方法才会被调用  



可以看到调用了PolicyManager的静态方法 

看一下这个PolicyManager   

咦  SDK看不了   代码中也调用不了   什么鬼 

看一下它所在的包名 :  

  • com.android.internal.policy.PolicyManager


!!!这根本就不在 android.jar  里

这怎么才能找到这个包里的源码呢   
用我上一篇博客说的:http://grepcode.com/  这个源码浏览网站     
找到这个PolicyManager  类里的:
public static Window  makeNewWindow(Context context) {
        return sPolicy.makeNewWindow(context);
    }
再看一下  sPolicy 是什么  



它是一个接口      被Policy实现   代码用反射构建了一个Policy对象  
(看来离Window类的真面目不远了)。。。。

Policy中的makeNewWindow()方法 
public Window  makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }
构造了一个PhoneWindow对象     这就是Window的实现类   也就是它调用了setContentView()  方法     方法内部:

判断没ContentParent 是否为null    是:调用installDecor() ,否:移除内部所有View   。
然后通过 mLayoutInflater.inflate()  
 LayoutInflater也是个抽象类    ,在PhoneWindow的构造方法中通过静态方法from创建的    它由哪个子类继承的还真不知道   
 

接着说installDecor()     ,就截取了开头一段  


首先初始化了 mDecor ,通过generateDecor方法  ,看一下:
protected  DecorView  generateDecor() {
        return new DecorView(getContext(), -1);
    }
然后找这个构造方法   发现 DecorView是PhoneWindow的内部类 并且是 private  final 类型
 private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
public DecorView(Context context, int featureId) {
     super(context);
     mFeatureId = featureId;
}
每个PhoneWindow中都有一个DecorView对象,它是PhoneView 的框架View(待会说它是干嘛的)

然后通过 generateLayut(mDecor)方法  把这个上面创建好的mDecor作为参数传递 


这个方法很长  ,找到有一段:
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
这里的layoutResource是 int值      对应我们mainfest中设置的theme主题所对应的屏幕布局
可以是R.layout.screen_custom_title;R.layout.screen_action_bar等等
现在我们知道了  DecorView 就是当前屏幕的除状态栏的区域,mContentParent对应的是里面除了ActionBar的区域
下面贴上这个图,你就可以看明白了(转自 工匠若水)

ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
把contentParent 变成了 ID_ANDROID_CONTENT 对应的ViewGroup    ,这是什么东西  ,看下这个   id
 public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
R.id.content ?  这怎么像是屏幕状态栏下方的内容区域的   id
通过findViewById给contentParent加上这么个 id 
好吧 暂时不理解    必须要看一下上面提到的    decor.addView  到底干了什么 ,看一下R.layout.screen_custom_title   这个布局吧   
// 文件位置:frameworks\base\core\res\res\layout            (frameworks包下)
<!--
This is a custom layout for a screen.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:fitsSystemWindows="true">
    <!-- Popout bar for action modes -->
    <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"
              android:theme="?attr/actionBarTheme" />

    <FrameLayout android:id="@android:id/title_container" 
        android:layout_width="match_parent" 
        android:layout_height="?android:attr/windowTitleSize"
        android:transitionName="android:title"
        style="?android:attr/windowTitleBackgroundStyle">
    </FrameLayout>
    <FrameLayout android:id="@android:id/content"
        android:layout_width="match_parent" 
        android:layout_height="0dip"
        android:layout_weight="1"
        android:foregroundGravity="fill_horizontal|top"
        android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
我们知道这个布局是一个屏幕的布局文件:上面的title_container是用来放自定义Title的容器,而下面的  content  就是放置我们设置的布局的容器  
再看一下 generateLayout的方法:
        View in = mLayoutInflater.inflate(layoutResource, null);
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
        mContentRoot = (ViewGroup) in;
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
啊哦 getDecorView
把整个手机界面给了DecorView 感觉要到了见证奇迹的时候了呢!!!
看下findViewById方法的实现 :
public View findViewById(int id) {
        return getDecorView().findViewById(id);
    }

getDecorView  显然是当前PhoneWindow中的DecorView对象  ,通过它把id 为 content的部分给了这个contentParent  然后return
记得  PhoneWindow中的setContentView 方法是这么写的  
 mLayoutInflater.inflate(layoutResID, mContentParent);
而这里的inflate方法是将LayoutResID对应的布局文件加载给mContentParent对应的ViewGroup
把我们为Activity设置的布局(layoutResId)设置给mContentParent(上面installDecor方法中的generateLayout方法return得到的contentParent)
到这里  我们已经把布局给放到DecorView中  接下来安卓系统就可以为我们显示界面了
在onResume()刚执行之后,界面还是不可见的,只有执行完Activity.makeVisible(),DecorView才对用户可见

最后拿一张别人的Android的窗口管理框架(转自ariesjzj










评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值