Android 4.2 SetContentViewプロセス分析(一)

11418 ワード

startActivityを呼び出して新しいActivityを起動すると、System ServerはSocketを介してZygoteに要求を送信し、この要求には「android.app.Activity Thread」パラメータがある.Zygoteは、このリクエストによりforkのサブプロセス(起動したactivityが属するプロセスがまだ起動していないと仮定)を実行し、このサブプロセスがAppに対応するプロセスである.このエントリ関数がActivity Threadのmain functionである.
Activity Thread classにはfunction handleLaunchActivityがあり、handleLaunchActivityの機能はActivityを追加する場所であり、main functionがhandleLaunchActivity functionにどのように呼び出すかのプロセス分析は今回の分析ではないので、handleLaunchActivityという関数を直接見てみましょう.
[ActivityThread.java]
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //...
        //      Activity  .      UI  (  View,
        //Window.)
        Activity a = performLaunchActivity(r, customIntent);  (1)
 
      if (a != null) {
            //...
            //  ViewRootImpl WindowManagerService, Surface   
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);  (2) 
            if (!r.activity.mFinished && r.startsNotResumed) {
                //    Activity       visible    , Activity
                //Manager Service     Activity    Pause state.
               
            }
        } else {
            //  Activity Manager Service     Activity.
           
        }
}

(1)
[ActivityThread.java]
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //1.   ActivityClientRecord       package information,
        //        Apk    package information.
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        //2.   ActivityClientRecord       component,    
        //  ActivityClientRecord  intent  component   .
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        //3.     Package information      ComponentName 
        // .
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
       
        Activity activity = null;
        try {
            //4.  ActivityClientRecord  package information  Class
            //Loader.
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            //5.   Class loader ComponentName    
            //mInstrumentation.newActivity        activity  .
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
           //...
        } catch (Exception e) {
           //...
        }
 
        try {
            //6.   ActivityClientRecord  package information    
            //  Application.
            Application app = r.packageInfo.makeApplication(false,
                           mInstrumentation);
           
            if (activity != null) {
                //7.    Activity    context       .
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title =
                   r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new
                    Configuration(mCompatConfiguration);
                //8.    Activity         Application.
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances,
                        config);
                //9.     activity   intent         
                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                //...
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }
                //...
                //10.       Activity  Create state.
                activity.mCalled = false;
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
          
           //...
 
        } catch (SuperNotCalledException e) {
            throw e;
 
        } catch (Exception e) {
           //...
        }
       
        return activity;
}
これまで、新しいActivityが起動されたときに、最初に呼び出されるのは
onCreate functionは、このfunctionで利用されます
setContentViewはUIインタフェースを設定する. 
[Activity.java]
public void setContentView(View view) {
        //               Window     UI  .
        getWindow().setContentView(view);         
        //  android 4.x    UI  ,       UI      
        //  .       ,           .
        initActionBar();     
}

getWindow().setContentView(view); この行のプログラムコードには2つの役割があります.WindowとViewです.SDKの記述によるWindowとViewの定義は以下の通りである.
Window
Abstract base class for a top-level window look andbehavior policy. An instance of this class should be used as the top-level viewadded to the window manager. It provides standard UI policies such as abackground, title area, default key processing, etc.
Windowは抽象クラスであり、主にtop windowの外観と動作、すなわちUIコンポーネントの描画とデフォルトの入力処理を制御するために使用される.
View
This class represents the basic building block foruser interface components. A View occupies a rectangular area on the screen andis responsible for drawing and event handling
ビューは画面の矩形を基本的に占有するUIユニットであり、絵画やイベントの処理に用いることができる.
getWindow回送のwindow物件は何ですか?setContentViewのViewオブジェクトは何を表していますか?次のように分析されます.
1.getWindow回送window物件.
[Activity.java]
public Window getWindow() {
        return mWindow;  
}
mWindowとは何か、これはactivityを追加したperformLaunchActivity functionから始める必要があります.performLaunchActivity functionを先に分析したところ、performLaunchActivityの
8つ目のステップでは、新しく生成するアプリケーションに新しいactivityを埋め込む、mWindowオブジェクトはこのときに生成される.直接的に見ると
8番目のステップで呼び出されたactivity.
attach関数の実作
[Activity.java]
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) {
             //...
             mWindow = PolicyManager.makeNewWindow(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;
}
ここの肝心な動作は2つのことをして、まず
PolicyManager.makeNewWindowは新しいWindowオブジェクトを作成し、新しいWindowオブジェクトをWindowManagerロールに設定します.
新しいウィンドウのアイテムは何ですか?
[PolicyManager.java]
public static Window makeNewWindow(Context context) {
       //sPolicy    IPolicy   ,            IPolicy   .
        return sPolicy.makeNewWindow(context);   
}
 
[Policy.java]
public Window makeNewWindow(Context context) {
       //   Window       PhoneWindow   .
        return new PhoneWindow(context);  
}
以上の分析から以下の推論が得られる.
        1. mWindow = PolicyManager.makeNewWindow(this);
              ==> mWindow = new PhoneWindow(this);
        2. mWindow.setWindowManager
              ==> new PhoneWindow(this). setWindowManager
WindowManagerは何ですか?
本来はmWindowがPhoneWindowのオブジェクトである以上、PhoneWindowカテゴリに行ってsetWindowManager functionの実作を探してみたが、見つからなかった.
それからPhoneWindowの親カテゴリWindowに行って探しました.
[Window.java]
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,  boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI,
                false);
        if (wm == null) {
            //1.  ServiceManger  Window Manger service proxy.
            wm =
     (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //2.   Window Manger service proxy   WindowManager.
        mWindowManager =  
               ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
 
[WindowManagerImpl.java]
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
}
以上の分析から分かる
WindowManagerは
WindowManagerImplオブジェクト
2.setContentViewのビューアイテム
前述の解析から、getWindowから伝わるmWindowはPhoneWindowオブジェクトであることが分かるので、PhoneWindowカテゴリから分析することができる.
[PhoneWindow.java]
@Override
public void setContentView(View view) {
        //      
        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT,
                        MATCH_PARENT));
    }
 
@Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        //1. mContentParent   ViewGroup  ,     null.
        if (mContentParent == null) {
            //  DecoreView,      
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        //2.   View   mContentParent (DecoreView) .
        mContentParent.addView(view, params);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
}
 
private void installDecor() {
        if (mDecor == null) {
            //DecorView   ,  FrameLayout       .
            mDecor = generateDecor();               
            //...
        }
        if (mContentParent == null) {
            //      
            mContentParent = generateLayout(mDecor);
                        //...
            } else {
           
            //...
            
            }   
        }
}
 
protected ViewGroup generateLayout(DecorView decor) {
                        //...
                View in = mLayoutInflater.inflate(layoutResource, null);
       // ViewGroup LayoutParams    DecoreView
       decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT,
                                                MATCH_PARENT));
       // findViewById    ID_ANDROID_CONTENT  ViewGroup    
       //   .
       ViewGroup contentParent =
                (ViewGroup)findViewById(ID_ANDROID_CONTENT);
      //...
      retrun contentParent;
}

から
setContentView
関数の2番目のステップ
わかる
,setContentView
の中
View
オブジェクトは
DecoreView (ViewGroup)
の子
View.
ここで結論を出します.performLaunchActivity関数でmInstrumentationを呼び出します.callActivity OnCreateは、次にActivityのonCreate functionをトリガし、一般的にonCreateで最初にsetContentViewを利用してUIコンポーネントを設定する.setContentViewこの関数はPhoneWindow,WindowManagerImpl,DecoreViewの3つのUI関連オブジェクトを持ち出す.
1.getWindowは、PhoneWindowオブジェクトであるmWindowを得る.
2.PhoneWindowオブジェクトを利用してWindowManagerImplの役割を設定.
3.PhoneWindow物件はDecoreViewのサブビューを設定する.