4

私は、ウィジェットをサポートFragmentし、選択の詳細を表示するためにユーザーを送信する検索結果を表示するアプリに取り組んでいます。これらはすべて正常に動作しますが、バックスタックに関して、Nexus 6 エミュレーターと実際のデバイスの間で一貫性のない動作が見られます。エミュレーターでは、FragmentActivity の詳細で [戻る] ボタンを押すと、ユーザーが検索結果フラグメントに戻され、すべてが期待どおりに機能します。実際の Nexus 6 デバイスでは、ユーザーはアプリのメニューを含む に戻ります (このアクティビティは、管理するフラグメントをバックスタックに追加する support を使用します)。SearchViewRecyclerViewFragmentActivityAppCompatActivityFragmentManager

private void replaceFragment(Fragment supportFragment) {
    String fragmentName = supportFragment.getClass().getSimpleName();
    supportFragmentManager.beginTransaction()
            .addToBackStack(fragmentName)
            .replace(R.id.frame_menu_container, supportFragment, fragmentName)
            .commit();
}

Fragment から FragmentActivity にユーザーを送信するコードは、エクストラを含むインテントです。

Intent intent = new Intent(getActivity(), PlayerDetailsActivity.class);
intent.putExtra(TransientPlayer.BUNDLE_KEY, transientPlayer);
startActivity(intent);

私はバックスタックで特別なことをしていません (まだ) - これはデフォルトの動作です。

ここで何が問題になる可能性がありますか? バックスタックでいくつかの読み取りを行いましたが、FragmentActivy から FragmentManager を使用していない Fragment に戻るときに、手動でバックスタックに何かを追加することについてはまだ何も見ていません。

編集 1:frame_menu_containerが定義されているレイアウト XML は次のとおりです。

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <FrameLayout
        android:id="@+id/frame_menu_container"
        android:layout_below="@id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout="@layout/fragment_home">
    </FrameLayout>

</RelativeLayout>

編集 2: OK、これが私の高レベルのアクティビティとフラグメントのテキストによる説明です。

NavigationMenuActivity、拡張しAppCompatActivityます。これは、すべてのフラグメントが必要に応じてスワップ インおよびスワップ アウトされる場所であり、メソッドSupportFragmentManagerが使用される場所です。replaceFragment()

次のフラグメントがあります。これらはすべて、静的情報を表示するか、REST 呼び出しを行ってデータを取得および表示するか、ユーザーがフィードバックを送信できるようにします。すべて extendsandroid.support.v4.app.Fragmentであり、ユーザーが移動できる他のフラグメントやアクティビティはありません。

  • ホームフラグメント
  • カレンダーフラグメント
  • 順位フラグメント
  • PlayerSearchFragment (下記参照)
  • フラグメントについて
  • フィードバックフラグメント

これらのフラグメントの機能の唯一の例外は、PlayerSearchFragmentも拡張するandroid.support.v4.app.Fragmentです。このフラグメントには、RecyclerViewユーザーがプレーヤーを検索するときに REST 呼び出しの結果を表示する が含まれています。結果が返され、ユーザーがリストから項目を選択すると、結果はPlayerDetailsActivitywhich extendsに送信されますFragmentActivity

PlayerDetailsActivityFragmentTabHost表示可能なプレーヤーに関するさまざまなタイプの情報を含むビューを使用します。これは、このパスの「終点」です。ユーザーが移動できる他のフラグメントやアクティビティはありません。ここが問題です。このアクティビティで [戻る] ボタンを押すと、ユーザーがPlayerSearchFragmentフラグメント (検索結果) に戻るようにすることが意図されています。NavigationMenuActivity実際の Nexus 6デバイスを使用している場合は、アクティビティに戻ります。

PlayerDetailsActivity戻るボタンが押されたときに呼び出される次のメソッドがありますが、常にゼロのエントリが表示されます。

@Override
public void onBackPressed() {

    FragmentManager fragmentManager = getSupportFragmentManager();
    int count = fragmentManager.getBackStackEntryCount();
    Log.i(TAG, "Backstack : There are " + count + " entries");
    for (int i = 0; i > count; i++) {
        FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
        Log.i(TAG, String.format("Backstack : id=%d, name=%s, shortTitle=%s, breadcrumbTitle=%s",
                backStackEntry.getId(),
                backStackEntry.getName(),
                backStackEntry.getBreadCrumbShortTitle(),
                backStackEntry.getBreadCrumbTitle()));
    }

    super.onBackPressed();
}

ハードウェアであろうとエミュレータであろうと、すべてのデバイスで同じエクスペリエンスが得られることを願っています。

4

4 に答える 4

1

これを試してみてください。うまくいけば、このエラーホールから抜け出すことができます。

この回答は回避策を提供しますが、実際に何が起こっているかはわかりません

@Override
public void onBackPressed() {

FragmentManager fragmentManager = getSupportFragmentManager();
int count = fragmentManager.getBackStackEntryCount();
Log.i(TAG, "Backstack : There are " + count + " entries");
if(count > 0){
    fragmentManager.popBackStack(); //or  popBackStackImmediate();
    for (int i = 0; i > count; i++) {
         FragmentManager.BackStackEntry backStackEntry = fragmentManager.getBackStackEntryAt(i);
         Log.i(TAG, String.format("Backstack : id=%d, name=%s, shortTitle=%s, breadcrumbTitle=%s",
            backStackEntry.getId(),
            backStackEntry.getName(),
            backStackEntry.getBreadCrumbShortTitle(),
            backStackEntry.getBreadCrumbTitle()));
   }
}else{
super.onBackPressed();
}

}

于 2015-08-30T05:53:27.660 に答える
1

addToBackStack(fragmentName)の後に呼び出されたいと思いますreplace(R.id.frame_menu_container, supportFragment, fragmentName)

何が起こるか教えてください。

于 2015-08-25T06:08:15.220 に答える
1

なぜこれを期待どおりに機能させることができなかったのかについてはまだ答えがありませんが、回避策があり、必要なことにはうまく機能します. 基本的に、私は Up および Back ナビゲーション コールバックをオーバーライドしPlayerDetailsActivity、インテント (データ付き) を使用して明示的にユーザーを に戻しますNavigationMenuActivity。インテントで送信するデータは、基本的に、私が から来ているかどうかを示す単なるブール値でPlayerDetailsActivityあり、そうである場合は、次のようにホーム フラグメントではなくそのフラグメントを表示します。

@Override
public void onBackPressed() {
    sendBackToMenu();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            sendBackToMenu();
            finish();
            return true;
    }
    return false;
}

private void sendBackToMenu() {
    Intent backToMenuIntent = new Intent(this, NavigationMenuActivity.class);
    backToMenuIntent.putExtra("FROM_PLAYER_DETAILS", true);
    startActivity(backToMenuIntent);
}

上記の変更は、継承元のクラスを変更し、上へのナビゲーションの ActionBar を有効にするためAppCompatActivityに以下を追加した後のものです。PlayerDetailsActivity.onCreate()

ActionBar actionBar = getSupportActionBar();
assert actionBar != null;
actionBar.setTitle(R.string.player_details);
actionBar.setDisplayHomeAsUpEnabled(true);

また、NavigationMenuActivity.onCreate()私はこれを行います:

if (getIntent().getBooleanExtra("FROM_PLAYER_DETAILS", false))
    replaceFragment(new PlayerSearchFragment());
else           
    replaceFragment(new HomeFragment());

これがこれを行うのに最も「適切な」方法であるかどうかはわかりませんが、うまく機能し、少数のハードウェア デバイスと Nexus 4/5/6 エミュレータで必要なことを実行します。

于 2015-08-30T13:45:01.297 に答える
1

シナリオによると、最初にトランザクションを BackStack に追加する必要はありません。これは、同じアクティビティ内のフラグメント間を移動する場合にのみ使用されるためです。

もう 1 つのポイントとして、バック プレスを実行してもフラグメントが取得されないということは、2 回クリックすることです。1 回のクリックで 2 番目のアクティビティが削除され、別のクリックでバックスタックに追加されたフラグメントが削除されます。あなたの情報については、フラグメントにはバックプレスコールバックがありません。アクティビティの onbackPressed() メソッドに依存しています

このコードを実行しようとしましたが、Nexus 5 デバイスで正しく実行されています。私が使用しているコードを添付していますが

public class MainActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    replaceFragment(new FragmentA());


}
private void replaceFragment(Fragment supportFragment) {

    getSupportFragmentManager().beginTransaction()
            .replace(R.id.frame_menu_container, supportFragment
            .commit();
}

}

FragmentAはここにあります:

 public class FragmentA extends Fragment {
    @Nullable
    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_a, null);

    view.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(getActivity(), AnotherActivity.class);
            startActivity(intent);
        }
    });
    return view;
}

}

そして別のアクティビティは次のようなものです:

public class AnotherActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.another_act);

}

}

問題に直面する必要はないと思います。

それでも問題が解決しない場合は、デバイス名を教えて、ここにコードを添付してください。テストしてお知らせします。

于 2015-08-28T12:50:45.103 に答える