こんにちは!
Fragmentにデータを受け渡す際にnewInstanceを使う訳を解説します。
私はFragmentを学び始めた頃にnewInstanceが登場した際に「これってコンストラクタで実装するのはダメなの?」「インスタンス後setterメソッドでデータを受け渡せば良いのでは?」と思いました。
今回はそんな疑問についてまとめました。
引数ありコンストラクタで実装すればよいのでは?
まず、結論から言うとコンストラクタで実装した場合、アプリがクラッシュしてしまう可能性があります。
ではなぜアプリがクラッシュしてしまうのでしょうか
実はFragmentの親であるActivityは端末のメモリ不足や画面回転時にActivityが破棄されてしまいます。親が破棄されれば必然的に子であるFragmentも破棄されてしまいます。
破棄後再生成されたActivityはFragmentManagerを使用してFragmentを再生成してくれます。
上記再生成のタイミングでFragmentManagerからは引数なしコンストラクタで再生成が実施されます。
上記時点でクラッシュします。
なぜ上記タイミングでクラッシュするかと言うと
Javaにはルールがあり引数ありコンストラクタのみ定義した場合に引数なしコンストラクタでインスタンス生成した場合にクラッシュします。
そのためクラッシュするのです。
もちろん、引数なしコンストラクタを定義した場合はクラッシュしませんがクラッシュしないようにするために引数なしコンストラクタを定義すると第三者は「何のために定義している?」と疑問を抱いてしまうのであまりおすすめしません。
インスタンス後setterメソッドでデータを受け渡せば良いのでは?
では、インスタンス生成後にsetterメソッドでデータを受け渡せば良いのではないでしょうか
結論、クラッシュはしません。
ですがsetterクラスで渡したデータが再生成時に初期化されてします。
再生成時にFragmentManagerから引数なしコンストラクタのみしか呼び出されないのでsetterメソッドは呼び出されません。
ではなぜnewIntanceだとデータは保持できるのでしょうか
newInstanceの中の実装を覗いてみましょう
public static HogeFragment newInstance(int data) {
Bundle args = new Bundle();
args.putInt("DATA", data);
MainFragment fragment = new HogeFragment();
fragment.setArguments(args);
return fragment;
}
setArgumentsで渡したBundleクラスがFragment再生成時にデータが復元されるのでデータが保持できる仕組みになっています。
またsetterクラスでは下記の2点の問題も発生します。
- インスタンス生成の一行、setterクラスの一行と計2行になる
- setterクラスをアクセス修飾子をpublic等に設定しないとダメ
インスタンス生成の一行、setterクラスの一行と計2行になる
newInstanceを使用するとインスタンス生成+データを受け渡しを行うのでnewInstanceの一行で済みますよね
setterクラスをアクセス修飾子をpublic等に設定しないとダメ
インスタンス生成後にデータを再度受け渡せる設計になってしまいます。こちらも第三者からすると「外部からデータを再度受け渡せるのか」と思ってしまう方が大半だと思います。
こちらも newInstanceはインスタンス生成+データを受け渡しのニコイチになっているでデータ受け渡しのみはできないので第三者は「インスタンス生成のみデータを渡している」という認識になります。
よってnewInstanceを使うべきですね!
コメント