2019年7月3日水曜日

androidx.fragment:fragment:1.1.0-alpha07 で userVisibleHint は deprecated になりました

ViewPager + FragmentPagerAdapter での setVisibleUserHint の挙動」の冒頭で軽く言及しましたが、androidx.fragment:fragment:1.1.0-alpha07 で FragmentPagerAdapter および FragmentStatePagerAdapter に変更が入っています。

1.1.0-alpha08 でも変更が入っており、以下の挙動は 1.1.0-rc01 で確認しています。


今まで FragmentPagerAdapter および FragmentStatePagerAdapter のコンストラクタでは FragmentManager だけを渡していましたが、1.1.0-alpha07 からはフラグ(int)も渡すように変わりました。

ここで指定できるフラグとして以下の2つが用意されています。
  • BEHAVIOR_SET_USER_VISIBLE_HINT
  • BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
今までの FragmentManager だけを渡すコンストラクタは deprecated になり、内部ではフラグとして BEHAVIOR_SET_USER_VISIBLE_HINT が指定されます。 public abstract class FragmentPagerAdapter extends PagerAdapter { ... @Deprecated public FragmentPagerAdapter(@NonNull FragmentManager fm) { this(fm, BEHAVIOR_SET_USER_VISIBLE_HINT); } ... } つまり BEHAVIOR_SET_USER_VISIBLE_HINT を指定すると、1.1.0-alpha06 までと同じ挙動になるということです。

ただし、この BEHAVIOR_SET_USER_VISIBLE_HINT 自体も deprecated です。 public abstract class FragmentPagerAdapter extends PagerAdapter { ... @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; ... } さらに Fragment の setUserVisibleHint(), getUserVisibleHint() も deprecated になりました。


では新しい BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT を指定するとどうなるのか、挙動を確認してみましょう。

FragmentPagerAdapter の getItem() で返す Fragment に次のようにログを入れました。 class SimpleFragment : Fragment() { override fun setUserVisibleHint(isVisibleToUser: Boolean) { super.setUserVisibleHint(isVisibleToUser) println("$position : setUserVisibleHint : $isVisibleToUser") } override fun onStart() { super.onStart() println("$position : onStart") } override fun onResume() { super.onResume() println("$position : onResume") } override fun onPause() { super.onPause() println("$position : onPause") } override fun onStop() { super.onStop() println("$position : onStop") } } class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewPager.adapter = MyPager(supportFragmentManager, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) } } この場合、ログは次のようになります。 System.out: 0 : onStart System.out: 1 : onStart System.out: 0 : onResume setUserVisibleHint() は呼ばれません。

position 0 と 1 の Fragment の onStart() が呼ばれ、その後 position 0 の Fragment だけ onResume() が呼ばれます。


この状態(position 0 が表示されいる状態)で右にスワイプして position 1 を表示すると、次のようなログが出ます。 System.out: 2 : onStart System.out: 0 : onPause System.out: 1 : onResume position 2 の Fragment が生成されて onStart() が呼ばれ、その後 position 0 の Fragment の onPause() が呼ばれて、position 1 の Fragment の onResume() が呼ばれます。


この状態(position 1 が表示されいる状態)で左にスワイプして再度 position 0 を表示すると、次のようなログが出ます。 System.out: 2 : onStop System.out: 1 : onPause System.out: 0 : onResume position 2 の Fragment が detach されるので onStop() が呼ばれています。
その後 position 1 の Fragment の onPause() が呼ばれて、position 0 の Fragment の onResume() が呼ばれます。


つまり、BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT を指定すると、PrimaryItem の Fragment だけが Lifecycle.State.RESUMED に達し、その他の Fragment は Lifecycle.State.STARTED で止まるという挙動になります。

onResume() が呼ばれるのは PrimaryItem の Fragment だけなので、「Fragment がユーザーに表示されたタイミングで xx したい」という場合に onResume() をトリガーとすることができるようになりました。



0 件のコメント:

コメントを投稿