ActivityのonCreateメソッドでPopupWindowによる異常の原因分析と解決策を表示

1920 ワード

前言


場合によっては、Activityに入るとPopupWindow(一般的な選択インタフェースなど)を表示する必要があります.ただし、PopupWindowはActivityに依存しているため、Activityの作成が完了していなければ、Activityがまだ完全に表示されていないままPopupWindowが表示されると異常現象が発生します.

問題の再現


ActivityのonCreate()メソッドで次のメソッドを呼び出します.
public void show( ){
    if( null != mPopupWindow ){
        mPopupWindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
    }
}

  プログラムを実行中に次のような異常が発生しました.
token is null

ソリューション


StackOverflowでこの問題を検索すると、原因分析はありませんが、「Android開発要旨」という本で答えを見つけました(P 158):
PopupWindowは、ダイアログボックスのように画面の固定位置からポップアップするのではなく、アンカーコントロールオブジェクトの位置に依存します.アンカーコントロールオブジェクトとは、インタフェースコンポーネントのコントロールです.PopupWindowの表示と機能は、アンカーコントロールの拡張インタフェースとして、そのコントロールオブジェクトの機能を強化するために、それを核心としています.
ポップアップ・ウィンドウは、ポップアップ・ウィンドウを構築して表示する前に、アンカー・コントロールが存在するコントロール・ツリーがウィンドウ管理サービスと接続されていることを保証する必要があります.ポップアップ・ウィンドウの表示中に、このウィンドウ・オブジェクトによって関連情報を取得する必要があるためです.インタフェースコンポーネントの構築過程において、ウィンドウ接続の確立は非同期過程であり、すなわちActivity.onCreate()などの関数が呼び出されると、インタフェースとウィンドウ管理サービスとの双方向通信接続は確立されず、ポップアップウィンドウを構築すると例外が放出されます.したがって、インタフェースコンポーネントが表示される場所でポップアップウィンドウを構築することが望ましい場合、ポップアップウィンドウオブジェクトの構築も非同期プロセスに変換することができる.
//  onCreate 
final View anchor = findViewById(R.id.anchor);
anchor.post(new Runnable(){
   @Override
  public void run(){
     //  
     PopupWindow window = createWindow();
     window.showAsDropDown(anchor);
  }
});

ウィンドウ管理サービスとの接続が確立する前に、インタフェースコンポーネントはViewを通過する.post関数から送信されたメッセージは静的キューに入れられ,通信接続の確立が完了した後,そのキューからメッセージを読み出して一つ一つ実行する.従って、このような実装モデルにより、ポップアップウィンドウの表示時にウィンドウ通信接続が正常に構築されることを保証することができる.
したがって、上記の問題に対して、最も簡単な処理方法は、PopupWindowを非同期で表示すればよい.
public void show( ){
    mView.post( new Runnable( ) {
        @Override
        public void run() {
            if( null != mPopupWindow ){
                mPopupWindow.showAtLocation(mView, Gravity.CENTER, 0, 0);
            }
        }
    });
}