Activity 的 Window 創建主要流程

首先是在 ActivityThreadperformLaunchActivity() 方法中創建Activity實例,並調用 Activity attach  方法

xref: /frameworks/base/core/java/android/app/ActivityThread.java

package android.app;
......
public final class ActivityThread extends ClientTransactionHandler {
    /** @hide */
    public static final String TAG = "ActivityThread";
    ......

    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ActivityInfo aInfo = r.activityInfo;
        ......
        
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            
            //通過類加載器cl創建Activity實例
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
        
          ......

         }
         
         ......

          try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            ......

            if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                ......
                Window window = null;
                ......
                appContext.setOuterContext(activity);
                
                //調用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, window, r.configCallback);
              if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
               ......

        } catch (SuperNotCalledException e) {
            throw e;

        } catch (Exception e) {
            ......
        }

        return activity;
    }

 

進入 Activity 的 attach 方法

xref: /frameworks/base/core/java/android/app/Activity.java

package android.app;

......

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        //實現了Window的 Callback 接口
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
    private static final String TAG = "Activity";
    private static final boolean DEBUG_LIFECYCLE = false;

    ......

    //定義mWindow、mDecor、mWindowManager
    private Window mWindow;

    private WindowManager mWindowManager;
    /*package*/ View mDecor = null;
    /*package*/ boolean mWindowAdded = false;

    ......

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

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

        //創建Activity所屬的Window對象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        //設置回調接口
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

        ......

        //通過Window 設置WindowManager
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();//獲取WindowManager
        ......
   }


   /**
     * 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)
     */
    //直接調用了Window的setContentView方法
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

    public Window getWindow() {
        return mWindow;
    }

接下來進入 PhoneWindow 的 setContentView 方法

xref: /frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

package com.android.internal.policy;
......

public class PhoneWindow extends Window implements MenuBuilder.Callback {

    private final static String TAG = "PhoneWindow";
    ......

    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;//將在  generateDecor(-1) 方法中創建
    
    ......

    // This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    ViewGroup mContentParent;//將在 generateLayout(mDecor) 方法中創建
    ......
    private LayoutInflater mLayoutInflater;
    ......
    //在其中一個構造方法中獲取 mLayoutInflater 對象
    public PhoneWindow(Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
    }
    
    /***
     *
     *
    
    1.首先創建 DecorView,DecorView是一個FrameLayout,是Activity中的頂級View
    DecorView包含標題欄和內容欄兩個部分
    
    2.之後直接通過我們常用的LayoutInflater的inflate方法
    直接將我們在XML文件中定義的佈局inflate進 DecorView 的內容欄裏面
    
     ***/
    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        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 {
            //直接將對應的佈局文件 inflate 進ViewGroup
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();//將會回調Activity中對應的方法
        }
        mContentParentExplicitlySet = true;
    }

    //以下是創建DecorView 和 mContentParent的過程
    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);//創建DecorView
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);//創建ViewGroup類型的mContentParent 
        
        ......

     }


   protected DecorView generateDecor(int featureId) {
        // System process doesn't have application context and in that case we need to directly use
        // the context we have. Otherwise we want the application context, so we don't cling to the
        // activity.
        Context context;
        if (mUseDecorContext) {
            Context applicationContext = getContext().getApplicationContext();
            if (applicationContext == null) {
                context = getContext();
            } else {
                context = new DecorContext(applicationContext, getContext());
                if (mTheme != -1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        return new DecorView(context, featureId, this, getAttributes());
    }


  protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.

        TypedArray a = getWindowStyle();
        ......

        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        ......

        return contentParent;
    }

    

其中 ID_ANDROID_CONTENT 這個id對應的 ViewGroup 就是 PhoneWindow 中的 mContentParent

在Window中有對應的定義如下

xref: /frameworks/base/core/java/android/view/Window.java

package android.view;
......
public abstract class Window {
    
    /**
     * The ID that the main layout in the XML layout file should have.
    */
    public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;


以下是 DecorView 的定義和PhoneWindow在同一路徑下,繼承了 FrameLayout

xref: /frameworks/base/core/java/com/android/internal/policy/DecorView.java

package com.android.internal.policy;

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章