Android 从源码看Activity的View是如何创建的

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/j550341130/article/details/82886309

先总结一下吧

个人理解, Android界面都是window, 所有的view都必须依赖于window, 包括activity中自己写的布局/Dialog/Toast/PopUpWindow/Menu菜单等等, 这些都各自对应着一个window.
( 关于window和View的其他理论知识请自行google/baidu )

1. window创建: Activity是在 ActivityThread 中的 performLaunchActivity 中启动, 在ActivityThread.performLaunchActivity中, 待启动activity的activity.attach方法被执行, 其内部会创建出window对象, 至此准备工作完成.
2. view添加到window: 在执行activity.setContentView时执行window.setContentView, 其内部会创建DecorView及其子View–mContentParent, 最终activity的布局被添加到mContentParent中, 完成添加过程.
3. 显示view: 虽然view已添加, 但是还没有显示, 在 ActivityThread 执行 handleResumeActivity 时 ( 可以认为是 activity.resume 时)activity.makeVisible被执行, 这时布局才会最终显示出来.


跟随源码

均省略了部分不相关 (kan bu dong) 的代码

1. window创建过程:

ActivityThread 类

    /**
    * activity启动是个复杂的过程, 最终会执行到此方法 
    */
    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);
                
				// activity的attach方法
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);
                // ...省略
            }
            r.paused = true;
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e);
            }
        }
        return activity;
    }

Activity类

    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) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);

        mWindow = new PhoneWindow(this); // 关键代码, 创建了window的子类PhoneWindow 
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        
        mUiThread = Thread.currentThread();
        mMainThread = aThread;
    }

2. view添加到window:

Activity类

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    public Window getWindow() {
        return mWindow; // 就是上面的PhoneWindow
    }

PhoneWindow

    @Override
    public void setContentView(int layoutResID) { // 还有好几个重载方法, 基本类似
        if (mContentParent == null) {
            installDecor(); // 初始化DecorView和mContentParent 
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
		if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent); // 把activity的布局添加到mContentParent中了
        }
        // ...
    }
    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(); // 创建 DecorView
            // ...
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor); // 创建mContentParent 
           // ...
        }
    }
    protected DecorView generateDecor() {
        return new DecorView(getContext(), -1);
    }
    protected ViewGroup generateLayout(DecorView decor) {
        // ...
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); // 传说中的android.R.id.content
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
        // ...
        return contentParent;
    }

3. 显示view:

ActivityThread 类

    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
        // ...
        if (r.activity.mVisibleFromClient) {
            r.activity.makeVisible();
        }
      	// ...
    }

Activity

    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE); // 显示DecorView
    }

为什么我这的PhoneWindow类查看不了

这是因为这个类在sdk中被隐藏了, 可以替换sdk中对应版本的android.jar.

  1. 第一步, 在 https://github.com/anggrayudi/android-hidden-api 下载常用android-sdk的android.jar;
  2. 第二步, 把jar包放在这里: \java\android-sdk-windows\platforms\android-xx, 这样就能愉快的查看这些藏起来的源码了.

so easy !

猜你喜欢

转载自blog.csdn.net/j550341130/article/details/82886309