Because Android manages the lifecycle of your Fragment, you should separate the problems of passing state into the Fragment through its bundle and injecting the Fragment with injectable deps. Usually, the best way to separate these is by providing a static factory method, which you might be calling the newInstance pattern.
public class YourFragment extends Fragment {
// Fragments must have public no-arg constructors that Android can call.
// Ideally, do not override the default Fragment constructor, but if you do
// you should definitely not take constructor parameters.
@Inject FieldOne fieldOne;
@Inject FieldTwo fieldTwo;
public static YourFragment newInstance(String arg1, int arg2) {
YourFragment yourFragment = new YourFragment();
Bundle bundle = new Bundle();
bundle.putString("arg1", arg1);
bundle.putInt("arg2", arg2);
yourFragment.setArguments(bundle);
return yourFragment;
}
@Override public void onAttach(Context context) {
// Inject here, now that the Fragment has an Activity.
// This happens automatically if you subclass DaggerFragment.
AndroidSupportInjection.inject(this);
}
@Override public void onCreate(Bundle bundle) {
// Now you can unpack the arguments/state from the Bundle and use them.
String arg1 = bundle.getString("arg1");
String arg2 = bundle.getInt("arg2");
// ...
}
}
Note that this is a different type of injection than you may be used to: Rather than getting a Fragment instance by injecting it, you are telling the Fragment to inject itself later once it has been attached to an Activity. This example uses dagger.android for that injection, which uses subcomponents and members-injection methods to inject @Inject-annotated
fields and methods even when Android creates the Fragment instance outside of Dagger's control.
Also note that Bundle is a general key-value store; I've used "arg1" and "arg2" instead of coming up with more creative names, but you can use any String keys you'd like. See Bundle and its superclass BaseBundle to see all of the data types Bundle supports in its get
and put
methods. This Bundle is also useful for saving Fragment data; if your app is interrupted by a phone call and Android destroys your Activity to save memory, you can use onSaveInstanceState
to put form field data into the Bundle and then restore that information in onCreate
.
Finally, note that you don't need to create a static factory method like newInstance
; you could also have your consumers create a new YourFragment()
instance and pass in a particular Bundle design themselves. However, at that point the Bundle structure becomes a part of your API, which you may not want. By creating a static factory method (or Factory object or other structure), you allow the Bundle design to be an implementation detail of your Fragment, and provide a documented and well-kept structure for consumers to create new instances.