TL;DR
最近、手元のプログラムの Support Library のバージョンを 25.0.1 から最新版に上げたところ、画面遷移のアニメーションが発生しなくなりました。調べてみると、 Support Library のバージョン 25.1.0 から、Fragment 表示時に onCreateAnimation が呼び出されるタイミングが変わっていました。
Support Library | onCreateAnimation が呼ばれるタイミング |
---|---|
25.0.1 | onCreateView の後、onViewCreated の前 |
25.1.0以降 | onResume の後 |
どんな問題が起こるか
Fragment#onResume より前に onCreateAnimation が呼び出されることを仮定したようなコードを書いていると1、アニメーションが正常に動作しない可能性があります。
この挙動の変化は、Support Library の 25.1.0 で FragmentTransaction の最適化機能が追加された影響ではないかと思います。最適化はFragmentTransaction.setAllowOptimization(false)
を設定するとオフにすることができ、また (25.1.0 でユーザーから悲鳴が上がったためか) 25.1.1 からはデフォルトでオフです。しかし、 onCreateAnimation の呼び出しタイミングについては、最適化がオンでもオフでも変化しません。
調査
テスト用フラグメントを作って確認してみました。ソースコード全体は GitHub においてあります。
コード抜粋
public class TestFragment extends Fragment {
public TestFragment() {
}
private void trace(String method) {
Log.i("LifeCycle", Integer.toHexString(this.hashCode()) + "#" + method);
}
@Override
public void onAttach(Context context) {
trace("onAttach");
super.onAttach(context);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
trace("onCreate");
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
trace("onCreateView");
return inflater.inflate(R.layout.fr_test, container, false);
}
(以下略)
フラグメントの表示は次のように行います。
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.setAllowOptimization(false); // 25.0.1 以前でビルドする時はコメントアウト
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
Fragment fragment = new TestFragment();
ft.replace(R.id.content_main, fragment);
ft.addToBackStack(null);
ft.commit();
実行結果
SDK 25.0.1 でビルドして実行すると、次のようになります。
I/LifeCycle: 869229f#onAttach
I/LifeCycle: 869229f#onCreate
I/LifeCycle: 869229f#onCreateView
I/LifeCycle: 869229f#onCreateAnimation
I/LifeCycle: 869229f#onViewCreated
I/LifeCycle: 869229f#onStart
I/LifeCycle: 869229f#onResume
SDK 25.1.0 以降でビルドして実行すると、次のようになります。
I/LifeCycle: c6cefb5#onAttach
I/LifeCycle: c6cefb5#onCreate
I/LifeCycle: c6cefb5#onCreateView
I/LifeCycle: c6cefb5#onViewCreated
I/LifeCycle: c6cefb5#onStart
I/LifeCycle: c6cefb5#onResume
I/LifeCycle: c6cefb5#onCreateAnimation
上記の実行結果は、 次の組み合わせで確認しています。
Compile SDK | Build Tool | Support Library |
---|---|---|
25 | 25.0.3 | 25.1.0 |
25 | 25.0.3 | 25.1.1 |
25 | 25.0.3 | 25.4.0 |
26 | 26.0.0 | 26.0.0 |
おわりに
onCreateAnimation の実行タイミングはドキュメントに明確な記載がなかったとはいえ、アニメーションのようにオブジェクトの生存タイミングに敏感な処理について、突然このような仕様変更を入れるのはひどいなかなかの大変更と思います。なお setAllowOptimization メソッドは API レベル 26 から setReorderingAllowed というメソッド名にすぐ変更になるなど、落ち着きがありません。この周辺の仕様はまた変化する可能性を踏まえて、ウォッチしておいた方が良さそうです。
-
本来 onCreateAnimation に Fragment の状態に依存するコードは書かないべきですが。 ↩