Activity Window 和View之间的关系

Activity Window 和View在Android中都承担着页面显示的共性。他们之间有怎样的关系呢?我们从三者的创建和点击触摸事件的分发响应两个方面做一个深入的分析。


一、首先我们从三者的创建顺序分析。


手机开机时默认会打开一些默认启动的程序。这其中包括桌面程序launcher。程序默认启动只需要在meanifest中配置即可:

        <activity android:name=".MainActivity">
            <intent-filter>

          <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
launcher配置特殊之处: 多添加的两行配置

        <activity android:name=".MainActivity">
            <intent-filter>
                <!-- 增加lancher配置-->
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />

                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

这样一个开机就显示的进程是怎么实现的呢?

public class Launcher extends Activity

        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,

                    View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener {

    static final String TAG = "Launcher";

    static final boolean LOGD = false;

     static final boolean PROFILE_STARTUP = false;

.......省略代码.......
}
说明launcher也是Activity。桌面程序和普通app一样都是在显示上归类为activity,只不过launcher在activity基础上装饰了更多的功能。

那么Activity Window 和View之间又是怎样调用的呢?

在App启动时主线程ActivityThread中Handler循环遍历消息

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;   
      }

当循环的Looper检查到 LAUNCH_ACTIVITY时即会执行handleLaunchActivity(r,null);

	private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {

        Activity a = performLaunchActivity(r, customIntent);

        -----------省略部分代码--------------

    }
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.voiceInteractor);

				--------------省略部分代码-------------
               }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to start activity " + component
                    + ": " + e.toString(), e);
            }
        }
        return activity;
    }

从这些源码可以看出,在activity window和view三者中是先实例化了activity。那么activity中应该有调用window和view的代码。

事实确实如此:在上面的代码中activity不为null时调用了attach方法,window正是在attach方法中首次出现,进行了实例化。

实际上Google的代码不断的更新。在5.1及其之前的代码中是这样实例化window的:

  mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
跟踪makeNewWindwo

31public interface More ...IPolicy {
32    public Window More ...makeNewWindow(Context context);
33
34    public LayoutInflater More ...makeNewLayoutInflater(Context context);
35
36    public WindowManagerPolicy More ...makeNewWindowManager();
37
38    public FallbackEventHandler More ...makeNewFallbackEventHandler(Context context);
39}

创建的是一个Window对象。

而在6.0(5.0就先不看了)及之后的代码中Window是这样实例化的:

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

	    ----------省略部分代码--------------
        mWindow = new PhoneWindow(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ----------省略部分代码--------------
}
实例化的是一个PhoneWindow对象。whatever!反正Window是在Activity创建之后才做了实例化。

三个目标搞懂了两个(1activity然后2Window),那么View应该是在Window之后才出现的吧,这是猜测,也是正确的。

话说百遍不如一张图,图省事,通过大数据搜扒了一张。


这是三者的调用顺序图。来验证一下第三步:

日常使用activity的onCreat时调用的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();
    }

getWindow()返回的正是在attach中实例化的PhoneWindow。setContextView具体操作是在Window中,在6.0版本中对应的是PhoneWindow。

@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
    if (mContentParent == null) {
        installDecor();
    } else {
        mContentParent.removeAllViews();
    }
    mContentParent.addView(view, params);
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

PhoneWindow类中有两个和视图相关的成员变量,一个是DecorView  mDecor ,另一个是ViewGroup  mContentParent

官方说明:


初次加载先实例化根视图:

private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();
        ...
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
        ...
    }
}

generateDecor()就是创建了一个DecorView。DecorView是PhoneWindow类中定义的一个内部类,它继承了FrameLayout,用来作为整个PhoneWindow的根视图。

mContentParent.addView(view, params);这一步调用了之后很多方法。最终会依次调用performMeasure(),performLayout(),performDraw()三个方法,终于开始了
控件层的测量,布局,绘制三个步骤,完成View的绘制。绘制并没有绘制在Window上而是PhoneWindow内的DecorView上。
PhoneWindow管理着整个屏幕的内容显示。包括状态栏,actionbar还有主题属性。Window中定义的requestFeature()等方法,有很多也与ActionBar属性相关。

So,到目前为止我们已经证明了上面图片的调用顺序是正确的。


二、Activity Window和View的触摸、点击事件的响应顺序是怎样的呢?





待续。。。。









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值