17

マスター/詳細レイアウト (1 つのアクティビティ、1 つの ListView フラグメント、1 つの詳細フラグメント) のアプリがあります。ユーザーが ListView 内のアイテムをクリックすると、フラグメント トランザクションによって、そのアイテムに対応する情報を含む詳細フラグメントが右側のペインにインスタンス化されます。詳細フラグメントが表示されると、最初のアクション バー ボタン/アイテムが非表示になり、3 つの新しい AB アイテム (完了/削除/キャンセル) が表示されます。ユーザーは、戻るボタンを押すか、3 つの AB 項目のいずれかを押すことで、右ペインを消去して初期 UI 状態に戻ることができます。

私が経験している問題は、ユーザーがアプリのホーム アイコン (つまり、「上へのナビゲーション」) を選択すると、アクティビティが再読み込みされることです (つまり、アクティビティが開始されたことを示すアニメーションが、アクション バーとUIが再描画されました)。この問題は、アプリのホーム アイコンが押されたときにのみ発生します。ユーザーが戻るボタンまたはキャンセル/完了/削除アクション バー ボタンを押すと、フラグメントは右ペインから単純に削除され、UI は「再読み込み」せずに初期状態に戻ります。

アクティビティの XML レイアウトは次のとおりです (LinearLayout 内では、prettify によってその行が非表示になっています)。

<fragment class="*.*.*.ListFragment"
        android:id="@+id/titles" android:layout_weight="1"
        android:layout_width="0px"
        android:layout_height="match_parent" />

<FrameLayout android:id="@+id/details" android:layout_weight="2"
        android:layout_width="0px"
        android:layout_height="match_parent" />

DetailsFragement の onCreate メソッドには、actionBar.setDisplayHomeAsUpEnabled ステートメントがあります。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);


    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

}

ListView フラグメントと Detail フラグメントの両方で、フラグメント内に onCreateOptionsMenu() および onOptionsItemSelected() メソッドが実装されています。詳細フラグメントのコードの下:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.edit_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    // some variable statements...

    switch (item.getItemId()) {
        case android.R.id.home:
            //Toast.makeText(getSherlockActivity(), "Tapped home", Toast.LENGTH_SHORT).show();
            onHomeSelectedListener.onHomeSelected();
            return true;

        case R.id.menu_edit_item_done:
            editedTask.setTitle(editedTaskTitle);
            onTaskEditedListener.onTaskEdited(editedTask, UPDATE_TASK, true);
            return true;

        default:
            return super.onOptionsItemSelected(item);

    }
}

ホスト アクティビティでは、onHomeSelectedListner を実装して、アプリのホーム アイコンの押下を処理します (つまり、「上へのナビゲーション」:

public void onHomeSelected(){

    FragmentManager manager = getSupportFragmentManager();
    FragmentTransaction ft = manager.beginTransaction();
    TaskFragment taskFragment = (TaskFragment)getSupportFragmentManager().findFragmentById(R.id.details);
    ft.remove(taskFragment);
    ft.commit();
    manager.popBackStack();

}

他のすべてのアクション バー ボタン (つまり、完了/削除/キャンセル) の処理を​​担当するアクティビティのリスナーは onTaskEditedListener であり、いくつかのデータを処理する他のコードは別として、上記と同じフラグメント トランザクションがあります。

更新(1/24) tyczj と straya のフィードバックに基づいて、アクティビティの onCreate()、onResume()、onPause() 内にログ ステートメントを配置して、onHomeSelected リスナーと onTaskEdited リスナーの違いを判断しました。「アップ ナビゲーション」イベント (つまり onHomeSelected) 中に onPause()、onCreate()、および onResume() が呼び出されることを確認できます。一方、onTaskEdited 呼び出し中 (つまり、戻るボタンまたは完了/削除/キャンセル プレス) では、これらのイベントは呼び出されません。

更新 (1/25) Mark Murphy の提案に基づいて、「case android.R.id.home」ステートメントの onHomeSelected メソッド呼び出しをコメントアウトして、Activity が何をするかを確認しました。ステートメントがないため、アプリは何もしないという考えでした。そうではないことがわかりました。リスナー メソッドを呼び出さなくても (つまり、フラグメントを削除する)、アクティビティが再開され、詳細フラグメントがフラグメント コンテナーから削除されます。

更新 (2/28) ウィンドウアニメーションを無効にすることで、メインアクティビティが再開されたという事実を一時的に回避します(私自身の回答で強調表示されています)。しかし、さらなるテストを通じて、バグを発見しました。Wolfram Rittmeyer のサンプル コードのおかげで、アップ ナビゲーション中に (マスター/詳細の単一レイアウトで) アクティビティが再開された本当の理由を突き止めることができました。バックスタックから、ホスティング アクティビティを開始する新しいインテントを作成していた ListView フラグメントの onOptionsItemSelected に、まだいくつかのコードが残っていました。そのため、アプリのホーム アイコンを押すと、アクティビティが再開されていました。2)私の最終的な実装(私自身の回答に示されています)では、

4

4 に答える 4

8

多くの調査と調査の結果、マスター/詳細構成の「アップナビゲーション」中にアクティビティが再開された唯一の理由は、ListView Fragment の onOptionsItemSelected にいくつかのコードを残したためであることが判明しました。他の場所にある私の完全なフラグメント トランザクション コードに。以下は、電話 (複数のアクティビティ) とタブレット (単一のアクティビティ/マルチペイン) の両方の構成で適切に動作するように「アップ ナビゲーション」を取得した最終的な実装です。Wolfram Rittmeyerのコード (コメント セクションのリンク) にいくつかのヒントがあり、問題を特定するのに役立ちました。

主なアクティビティ:フラグメントをホストし、その他のアプリ固有の操作を実行します

ListView Fragment:テーブル構成での「上へのナビゲーション」を処理します

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            if(mDualPane){
                FragmentManager manager = getSherlockActivity().getSupportFragmentManager();
                FragmentTransaction ft = manager.beginTransaction();
                DetailFragment detailFragment = (DetailFragment)manager.findFragmentById(R.id.details);
                ft.remove(detailFragment);
                ft.commit();
                manager.popBackStack();
                getSherlockActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSherlockActivity().getSupportActionBar().setHomeButtonEnabled(false);
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }
}

詳細フラグメント:電話構成でのナビゲーションを処理します

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);

    // Sets "up navigation" for both phone/tablet configurations
    ActionBar actionBar = getSherlockActivity().getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) {
        case android.R.id.home:
            if(!mDualPane){
                Intent parentActivityIntent = new Intent(getSherlockActivity(), MainActivity.class);
                parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(parentActivityIntent);
                getSherlockActivity().finish();
            }
            return true;

        // Other case statements...

        default:
            return super.onOptionsItemSelected(item);
    }

}
于 2013-02-27T02:40:36.537 に答える
3

ナビゲーション デザイン パターンを見ると、ホーム ボタンが押されたときに開始アクティビティに戻りたいことがわかります。

たとえば、2 つのアクティビティがあり、それらA1を呼び出すとしA2ます。A1 の何かをクリックすると、A2 に移動します。ユーザーがホームボタンを押した場合は、A1 に戻して、このようなアクティビティまでのすべてのスタックをクリアする必要があります

Intent intent = new Intent(this, A1.class);  
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

これがフラグのIntent.FLAG_ACTIVITY_CLEAR_TOP機能です

設定されていて、起動されているアクティビティが現在のタスクで既に実行されている場合、そのアクティビティの新しいインスタンスを起動する代わりに、その上にある他のすべてのアクティビティが閉じられ、このインテントがに配信されます (現在上)新しいインテントとしての古いアクティビティ。

たとえば、アクティビティ A、B、C、D で構成されるタスクを考えてみましょう。アクティビティ B のコンポーネントに解決されるインテントで D が startActivity() を呼び出すと、C と D は終了し、B は指定されたインテントを受け取ります。となり、スタックは次のようになります: A, B.`

上記の例で現在実行中のアクティビティ B のインスタンスは、ここで開始した新しいインテントを onNewIntent() メソッドで受け取るか、それ自体が終了して新しいインテントで再開されます。起動モードが「複数」(デフォルト) であると宣言されていて、同じインテントで FLAG_ACTIVITY_SINGLE_TOP を設定していない場合は、終了して再作成されます。他のすべての起動モードの場合、または FLAG_ACTIVITY_SINGLE_TOP が設定されている場合、このインテントは現在のインスタンスの onNewIntent() に配信されます。

この起動モードは、FLAG_ACTIVITY_NEW_TASK と組み合わせて使用​​することもできます。タスクのルート アクティビティを開始するために使用すると、そのタスクの現在実行中のインスタンスがフォアグラウンドに移動し、ルート状態にクリアされます。これは、通知マネージャーからアクティビティを起動する場合などに特に役立ちます。

于 2013-01-23T04:42:59.923 に答える
0

アクティビティ内でのみ Up ボタンを処理する必要があると思います。電話を使用している場合、上ボタンはそのフラグメントのラッパーとして機能するアクティビティによって処理されますが、タブレット (マスター/詳細パターン) では、とにかくそれは必要ありません

于 2013-02-21T01:42:01.037 に答える
0

してはいけないこと: 中断してから super.onOptionsItemSelected(item) を返します。

アップデート:

つまり、ビューで発生したことに基づいてアクティビティが「再起動」されたと言っていますが、さまざまなライフサイクルメソッドでログを使用して、アクティビティ (およびそのフラグメント) に何が起こるか、何が起こらないかを確認できますか? そうすれば、診断を進める前に、現在の (誤った) 動作が何であるかを確認できます。

アップデート:

OK、動作について確認してください:)「マスター/詳細レイアウト(1アクティビティ/ 2フラグメント)の「アップナビゲーション」を実装する正しい方法は何ですか?」という質問に関して:典型的な方法は、2つのフラグメントが得られたということです単一の FragmentTransaction 内に追加され、単純に popBackStack を削除して以前の状態に戻ります。FragmentTransaction 内の Fragment を手動で削除してからバックスタックをポップすることで、倍増していると思います。popBackStack だけを試してください。ああ、確かに一貫性を保つために、ActionBarSherlock と support.v4 を使用しているので、FragmentActivity (アクティビティではなく) と SherlockFragment を使用していますか?

于 2013-01-23T04:46:50.993 に答える