Windowに関する知識

6564 ワード

Activityの階層はActivity->PhoneWindow->decorView->appbarとcontentViewに分けられ、phoneWindowはwindowの唯一の実装であり、phoneWindowがactivityのattachメソッドでActivityを初期化するattachはAMSがActivity ThreadのhandleMessageでlaunchActivityメソッド呼び出しを実行し、attachを実行するとActivityのonCreateメソッドを実行する
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 //....
        if (activity != null) {
            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);
//....
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
 }

ユーザーがsetContentViewを呼び出すと、継承された関係によって2つに分けられます.1.ActivityまたはFragmentActivityを継承してwindowを直接呼び出すsetContentViewメソッド
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

PhoneWindowでの疑似コードは
@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        installDecor();
    }
   //  app     
    mLayoutInflater.inflate(layoutResID, mContentParent);
}

最初のステップは、mContentParentが空の場合、つまりdeCorViewが初期化されていない場合、installDecorを実行することです.
private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);
        if (decorContentParent != null) {
            mDecorContentParent = decorContentParent;
        } else {
          //...
        }
}

ここでgenerateDecorはnewのDecorViewです
protected DecorView generateDecor() {
    return new DecorView(getContext(), -1);
}
//   
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker

generateLayoutメソッドは主にdecorViewのプロパティを初期化します.例えば、タイトルの設定、アイコンのページスタイルの設定などです.私たちはコードで全画面を設定します.なぜsetCotentViewの前にこの理由がありますか.
    if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
        requestFeature(FEATURE_NO_TITLE);
    } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
        // Don't allow an action bar if there is no title.
        requestFeature(FEATURE_ACTION_BAR);
    } 

2.継承AppCompatActivityは、コンパイルされたシステムバージョンに従ってオブジェクトmDelegateオブジェクト@Override public void setContentView(@LayoutResint layoutResID){getDelegate().setContentView(layoutResID);setContentViewは最終的にAppCompatDelegateImplV 7のsetContentViewメソッドを呼び出す
@Override
public void setContentView(int resId) {
    ensureSubDecor();
    ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
    contentParent.removeAllViews();
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    mOriginalWindowCallback.onContentChanged();
}

EnsureSubDecorメソッドは、最終的に設定に従って「subDecor」をロードするレイアウトを呼び出し、activityとは異なりdecorViewを使用しません.
private ViewGroup createSubDecor() {
    TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
    //      
    if (a.getBoolean(R.styleable.Theme_windowNoTitle, false)) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
    } else if (a.getBoolean(R.styleable.Theme_windowActionBar, false)) {
        // Don't allow an action bar if there is no title.
        requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR);
    }
    final LayoutInflater inflater = LayoutInflater.from(mContext);
    ViewGroup subDecor = null;
    if (!mWindowNoTitle) {
        if (mIsFloating) {
            // If we're floating, inflate the dialog title decor
            subDecor = (ViewGroup) inflater.inflate(
                    R.layout.abc_dialog_title_material, null);
            // Floating windows can never have an action bar, reset the flags
            mHasActionBar = mOverlayActionBar = false;
        } else if (mHasActionBar) {
            // Now inflate the view using the themed context and set it as the content view
            subDecor = (ViewGroup) LayoutInflater.from(themedContext)
                    .inflate(R.layout.abc_screen_toolbar, null);

            mDecorContentParent = (DecorContentParent) subDecor
                    .findViewById(R.id.decor_content_parent);
        }
    } else {
        if (mOverlayActionMode) {
            subDecor = (ViewGroup) inflater.inflate(
                    R.layout.abc_screen_simple_overlay_action_mode, null);
        } else {
            subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
        }
    // Now set the Window's content view with the decor
    mWindow.setContentView(subDecor);
    return subDecor;
}

WindowaManagerはactivityのattachで初期化され、それ自体がインタフェースクラスであり、インタフェースViewManagerを継承する.この3つの方法は、WindowManagerがactivity制御Viewに提供する
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

WindowaManager実装クラスはWindowManagerImplで、中はWindowManagerGlobalを取得して、具体的な方法の実装です
public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }
    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }
}

WindowManagerには3つの配列が格納されています
//     View
private final ArrayList mViews = new ArrayList();
private final ArrayList mRoots = new ArrayList();
//  view   
private final ArrayList mParams =
        new ArrayList();