65
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Fragmentによる画面遷移でハマった

Last updated at Posted at 2017-11-16

やりたいこと

Fragmentで作られた画面A,B,Cがあり、A->B->Cと遷移し、
Cでバックキーをタップした際は、Bを飛ばしてAに戻りたい

レイアウト

ベースのレイアウト

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

画面Aのレイアウト

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#00000000"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/button"
        android:text="Fragment A Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

device-2017-11-16-141547.png

画面Bのレイアウト

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#00000000"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/button"
        android:text="Fragment B Button"
        android:layout_gravity="right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

device-2017-11-16-141554.png

画面Cのレイアウト

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00000000">

    <Button
        android:id="@+id/button"
        android:text="Fragment C Button"
        android:layout_gravity="bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

device-2017-11-16-141600.png

画面遷移処理

画面Aの追加処理

    val transaction = supportFragmentManager.beginTransaction()
    transaction.add(R.id.container, FragmentA.newInstance())
    transaction.commit()

画面Bへの遷移処理

    val transaction = fragmentManager.beginTransaction()
    transaction.replace(R.id.container, FragmentB.newInstance())
    transaction.addToBackStack(null)
    transaction.commit()

画面Cへの遷移処理

    val transaction = fragmentManager.beginTransaction()
    transaction.replace(R.id.container, FragmentC.newInstance())
    // Bを飛ばしてAに戻りたいのでbackStack追加しない
    //transaction.addToBackStack(null) 
    transaction.commit()

上記実装で画面A->B->Cと遷移し、バックキーを押すと、なぜか画面Aと画面Cが両方表示されてしまう。
device-2017-11-16-141606.png

原因

http://extra-vision.blogspot.jp/2016/02/android-fragment-transaction-back-stack.html
上記リンクが参考になった。
addToBackStackはfragmentをスタックに積む命令ではなく、fragment操作のトランザクションを記録する命令であり、バックキータップ時の処理はスタックに積んだfragmentをpopしているわけではなく、記録されたトランザクションの逆の操作を行っている、ということである。
今回のケースでは、

add(fragment A) トランザクション記録しない
replace(fragment B) トランザクション記録する
replace(fragment C) トランザクション記録しない

となっており、replaceは内部的にはremoveとaddを連続で行うのと同じことなので、展開すると、

add(fragment A) トランザクション記録しない
remove(fragment A), add(fragment B) トランザクション記録する
remove(fragment B), add(fragment C) トランザクション記録しない

となる。この状態でバックキーをタップすると、記録されたトランザクションの逆の操作を行うため、

remove(fragment A), add(fragment B) トランザクション記録する

の逆の操作である、

remove(fragment B), add(fragment A)

の操作が実行され、fragmentAが最前面に表示され、fragmentCは残るということになる。

解決策

画面Cでバックキーをタップした際の処理をフックし、自身を殺した上でpopBackStackする

    fragmentManager.beginTransaction().remove(this).commit()
    fragmentManager.popBackStack()

もしくは、addToBackStack時にタグを指定しておき、タグ指定でpopBackStackする。

    transaction.replace(R.id.container, FragmentB.newInstance())
    transaction.addToBackStack("fragmentA")
....
....
    fragmentManager.popBackStack("fragmentA", FragmentManager.POP_BACK_STACK_INCLUSIVE)
65
61
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
65
61

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?