Android作成ウィンドウ(二)Dialogの作成

5623 ワード

Android作成ウィンドウ(一)作成アプリケーションウィンドウでは、アプリケーションウィンドウの作成手順について説明し、Dialogの作成手順について説明します.Dialogの作成とアプリケーションウィンドウの作成には似たような点がたくさんあります.前のファイルで紹介したので、ここで似たようなところをスキップしました.
まず、Dialogを表示する方法を見てみましょう.
Dialog dialog=new Dialog(MainActivity.this);
dialog.setContentView(R.layout.dialog);
dialog.show();

Dialogのコードを表示するのは簡単ですが、次は一歩一歩分析してみましょう.
1.アプリケーションウィンドウを作成します.まずActivityオブジェクトを作成します.Dialogを作成することもDialogオブジェクトを作成することになります.まず、Dialogのコンストラクション関数を見てみましょう.
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    ...
    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    final Window w = new PhoneWindow(mContext);
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);

    mListenersHandler = new ListenersHandler(this);
}

やはりアプリウィンドウと同じように、まずWindowオブジェクトを作成しました.
2.次にcontentviewを設定します.
public void setContentView(@LayoutRes int layoutResID) {
    mWindow.setContentView(layoutResID);
}

Dialogはこのタスクをwindowに任せて完了し、Activityと同様にwindowでレイアウトファイルを追加します.PhoneWindowのsetContentViewメソッド:
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();
    } 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);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

Android作成ウィンドウ(一)作成アプリケーションウィンドウでこの方法を紹介していますが、ここではあまりお話ししません.これはレイアウトファイルをdecorviewに追加することです.
3.WindowにDecorViewを追加して表示する
このステップはDialogのshowメソッドで完成しました.ソースコードを見てみましょう.
/**
 * Start the dialog and display it on screen.  The window is placed in the
 * application layer and opaque.  Note that you should not override this
 * method to do initialization when the dialog is shown, instead implement
 * that in {@link #onStart}.
 */
public void show() {
    if (mShowing) {
        if (mDecor != null) {//  decorview           ,
            if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
            }
            mDecor.setVisibility(View.VISIBLE);
        }
        return;
    }

    mCanceled = false;

    if (!mCreated) {
        dispatchOnCreate(null);
    } else {
        // Fill the DecorView in on any configuration changes that
        // may have occured while it was removed from the WindowManager.
        final Configuration config = mContext.getResources().getConfiguration();
        mWindow.getDecorView().dispatchConfigurationChanged(config);
    }

    onStart();
  // decorview       
    mDecor = mWindow.getDecorView();

    if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
        final ApplicationInfo info = mContext.getApplicationInfo();
        mWindow.setDefaultIcon(info.icon);
        mWindow.setDefaultLogo(info.logo);
        mActionBar = new WindowDecorActionBar(this);
    }

    WindowManager.LayoutParams l = mWindow.getAttributes();
    if ((l.softInputMode
            & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
        WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
        nl.copyFrom(l);
        nl.softInputMode |=
                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
        l = nl;
    }

  // decorView   window 
    mWindowManager.addView(mDecor, l);
    mShowing = true;

    sendShowMessage();
}

showメソッドはまずmDecorがnullとして保存されているかどうかを判断し、nullでなければ表示し、nullであれば初期化し、decorviewをwindowに追加します.
以上の3つのステップから、Dialogの作成とActivityの作成のプロセスには多くの類似点があることがわかる.
Dialogのdismissを見てみましょう
/**
 * Dismiss this dialog, removing it from the screen. This method can be
 * invoked safely from any thread.  Note that you should not override this
 * method to do cleanup when the dialog is dismissed, instead implement
 * that in {@link #onStop}.
 */
@Override
public void dismiss() {
    if (Looper.myLooper() == mHandler.getLooper()) {
        dismissDialog();
    } else {
        mHandler.post(mDismissAction);
    }
}

void dismissDialog() {
    if (mDecor == null || !mShowing) {
        return;
    }

    if (mWindow.isDestroyed()) {
        Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!");
        return;
    }

    try {
        mWindowManager.removeViewImmediate(mDecor);
    } finally {
        if (mActionMode != null) {
            mActionMode.finish();
        }
        mDecor = null;
        mWindow.closeAllPanels();
        onStop();
        mShowing = false;

        sendDismissMessage();
    }
}

これは比較的簡単で、Dialogが閉じるとWindowManagerでdecorviewをwindowから削除します.
ソース分析によるAndroidウィンドウの作成:Android作成ウィンドウ(一)アプリケーションウィンドウAndroid作成ウィンドウ(二)Dialog Android作成ウィンドウ(三)Toastの作成