1. 程式人生 > >Activity的建立(從Activity的角度理解IWindowSession)

Activity的建立(從Activity的角度理解IWindowSession)

前言      本篇主要講從Activity的角度來理解Window、DecorView、WindowManager、IWindowSession,以及ViewRootImpl與

1 建立Activity

     我們知道App程序的入口函式是ActivityThread中的main()函式,ActivityThread中有個函式handleLaunchActivity,Activity就是在這個函式中啟動的,那麼接下來我們看看 ActivityThread#handleLaunchActivity原始碼:
privatevoid handleLaunchActivity(ActivityClientRecord r, Intent customIntent, 
String reason) { ...... //函式1 返回一個Activity 例項 Activity a =performLaunchActivity(r, customIntent); if (a !=null) { r.createdConfig =new Configuration(mConfiguration); reportSizeConfigurations(r); Bundle oldState = r.state;
//函式2 呼叫handleResumeActivityhandleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished &&!r.startsNotResumed, r.lastProcessedSeq, reason); if (!r.activity.mFinished && r.startsNotResumed) { performPauseActivityIfNeeded(r, reason);
if (r.isPreHoneycomb()) { r.state = oldState; } } } else { // If there was an error, for any reason, tell the activity manager to stop us.try { ActivityManagerNative.getDefault() .finishActivity(r.token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } }
     接下來將對兩個至關重要的1、2函式進行分析。

(1)函式1 :ActivityThread#performLaunchActivity原始碼:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
        //aInfo 中存放了Activity、receiver節點資訊
        ActivityInfo aInfo = r.activityInfo;
        .........//完成一些準備工作
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //mInstrumentation為Instrumentation型別,該例項呼叫newActivity建立一個Activity例項,其內部使用到了反射機制
           // 至於怎麼建立的稍後來講。
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
             .......
        } catch (Exception e) {
             .......
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ......
            if (activity !=null) {
                //建立上下文例項
                Context appContext =createBaseContextForActivity(r, activity);
                .......
 activity.attach(appContext, this, getInstrumentation(), r.token,<pre data-original-code="" private="" activity="" performlaunchactivity(activityclientrecord="" r,="" intent="" customintent{"="" data-snippet-id="ext.3078aa40e37abac54d2a81092277cc8d" data-snippet-saved="false" data-codota-status="done" style="font-family: Monaco, Consolas, Courier, 'Lucida Console', monospace; line-height: 16px; white-space: pre-wrap; background-color: whitesmoke;">                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);
.......//呼叫Activity中的onCreate方法if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); } ....... } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { ....... } return activity;}  從上述程式碼不難看出,performLaunchActivity有三個主要的作用:
a:通過反射建立Activity例項 b:呼叫Activity的onCreate方法,而在Activity#onCreate方法中通過呼叫setContentVIew來設定UI元素。 c:Activity#attach方法,在這個方法中初始化了mWindow。

(2)函式2:ActivityThread#handleResumeActivity原始碼:

finalvoid handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        
            if (r.window==null&&!a.mFinished && willBeVisible) {
                //獲取window物件
                r.window= r.activity.getWindow();
                 //獲取View物件,這個View是最頂層的View
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                 //獲取ViewManager物件
                ViewManager wm = a.getWindowManager();
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor;
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded =true;
                    r.mPreserveWindow =false;
                    //獲取ViewRootImpl物件 windowmanager通過它來操作view(window)// ViewRootImpl,在
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl !=null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient &&!a.mWindowAdded) {
                    a.mWindowAdded =true;
                    //把剛剛獲取view放置到wm中wm.addView(decor, l);
                }
            } elseif (!willBeVisible) {
                r.hideForNow =true;
            }

           
    }

2 建立Window、DecorVIew、WindowManager

    下面我們考慮Activity如何和View、Window聯絡在一起?這個問題在《DecorView與window的建立》這篇已經講過,在這裡,我再來捋一遍,首先在Activity#onCreate方法中呼叫了setContentView,我們看下它的原始碼:

(1)建立Window、WindowManager

Activity#setContentView、getWindow:
public void setContentView(@LayoutRes int layoutResID) {
     getWindow().setContentView(layoutResID);  //呼叫getWindow方法,返回mWindow
     initWindowDecorActionBar();
}
...
public Window getWindow() {   
     return mWindow;
}
       方法Activity#getWindow返回Window型別,那麼Window是什麼鬼?看字義就是視窗吶,檢視原始碼我們知道Window是個抽象類,在android 它的實現類是PhoneWindow,PhoneWindow存在於Activity中,它裡面包括放置標題欄、DecorView等。瞭解更多參見《》。 上面的mWindow又是在Activity#attach方法中初始化的,原始碼如下:
finalvoid 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) {
        attachBaseContext(context);

        mFragments.attachHost(null/*parent*/);
        //初始化mWindow
        mWindow =newPhoneWindow(this, window);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        .....
        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();
        mCurrentConfig = config;
}
    看,初始化mWindow是通過new PhoneWindow(),已經明白了Window,下面我看看WindowManager,上面mWindow 呼叫了setWindowManager方法,其原始碼如下:
publicvoid setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm ==null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
再看WindowManagerImpl#createLocalWindowManager原始碼:
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
}
    在這裡new了一個WindowManagerImpl賦值給了mWindowManager,其實WindowManagerImpl是WindowManager實現類,在這篇《WindowManger與window之基礎篇》文章提到過,好吧,再把WindowManagerImpl原始碼貼過來:
public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;
    private IBinder mDefaultToken;
    public WindowManagerImpl(Display display) {
        this(display, null);
    }
    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Display display) {
        return new WindowManagerImpl(display, mParentWindow);
    }
    ......
}
好了,現在window、和windowManager都清楚了。

(2)建立DecorView

Activity#setContentView——>PhoneWindow#setContentView,原始碼如下:
@Override
publicvoid setContentView(int layoutResID) {
        //mContentParent 初始值為null ,為ViewGroup型別,//在繪製它的時候,會連他的的子類一起繪製。if (mContentParent ==null) {
            //在這個方法中建立DecorViewinstallDecor();
        } elseif (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            //載入ID為layoutResID的佈局
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
      ......
}
繼續來看PhoneWindow#installDecor:
privatevoid installDecor() {
        mForceDecorInstall =false;
        if (mDecor ==null) {
            // 1mDecor 初始值為null,為Decor型別
            mDecor =generateDecor(-1);
            ......
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent ==null) {
           //2 若mContentParent為null,初始化mContentParent
            mContentParent =generateLayout(mDecor);
            ......
            } else {
               //建立標題欄
                mTitleView = (TextView) findViewById(R.id.title);
                if (mTitleView !=null) {
                    if ((getLocalFeatures() & (1<< FEATURE_NO_TITLE)) !=0) {
                        final View titleContainer = findViewById(R.id.title_container);
                        if (titleContainer !=null) {
                            titleContainer.setVisibility(View.GONE);
                        } else {
                            mTitleView.setVisibility(View.GONE);
                        }
                        mContentParent.setForeground(null);
                    } else {
                        mTitleView.setText(mTitle);
                    }
                }
            }
           ......
          
}
這個方法有三個作用:
a:呼叫PhoneWindow#generateDecor初始化mDecor; b:若mContentParent為null,則呼叫generateLayout初始化mContentParent; c:建立標題欄,從而也證明了,標題欄是在Activity最頂級View(DecorView)裡面的;
還有,注意這裡面兩個函式1、2 。 接下來,繼續來看函式1:PhoneWindow#generateDecor
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().getResources());
                if (mTheme !=-1) {
                    context.setTheme(mTheme);
                }
            }
        } else {
            context = getContext();
        }
        returnnewDecorView(context, featureId, this, getAttributes());
}
     好吧,到這裡,小編已經暈頭轉向了,不知你如何,但是終於“柳暗花明又一村”了,已經出來了DecorView的構造方法,繼續往下看DecorView到底是什麼鬼?
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
   ......
}
    很明顯DecorView繼承了FrameLayout,說明它也是個ViewGroup。 函式2:PhoneWindow#generateLayout:
protected ViewGroup generateLayout(DecorView decor) {
        // Apply data from current theme.獲取屬性值
        TypedArray a = getWindowStyle();
        ......//對屬性值進行處理//根據不同情況取得不同的標題欄資源int layoutResource;
        int features = getLocalFeatures();
        // System.out.println("Features: 0x" + Integer.toHexString(features));if ((features & (1<< FEATURE_SWIPE_TO_DISMISS)) !=0) {
            layoutResource = R.layout.screen_swipe_dismiss;
        } elseif ((features & ((1<< FEATURE_LEFT_ICON) | (1<< FEATURE_RIGHT_ICON))) !=0) {
            ......
        } elseif ((features & ((1<< FEATURE_PROGRESS) | (1<< FEATURE_INDETERMINATE_PROGRESS))) !=0&& (features & (1<< FEATURE_ACTION_BAR)) ==0) {
            ......
        } elseif ((features & (1<< FEATURE_CUSTOM_TITLE)) !=0) {
            ......
        } elseif ((features & (1<< FEATURE_NO_TITLE)) ==0) {
            ......
        } elseif ((features & (1<< FEATURE_ACTION_MODE_OVERLAY)) !=0) {
            layoutResource = R.layout.screen_simple_overlay_action_mode;
        } else {
            // Embedded, so no decoration is needed.
            layoutResource = R.layout.screen_simple;
            // System.out.println("Simple!");
        }
        mDecor.startChanging();