Enhance Fragments

Csaba Kozák edited this page Feb 19, 2017 · 18 revisions

10/6/2017 The 4.3.1 release is out !

Using AndroidAnnotations

Questions?

Enjoying AndroidAnnotations

Improving AndroidAnnotations

Extending AndroidAnnotations

Clone this wiki locally

Support for FragmentActivity

Since AndroidAnnotations 2.1

Prior to AndroidAnnotations 2.6, there was no support for fragment injection. However, we made sure that at least extending FragmentActivity instead of Activity didn't break AndroidAnnotations:

@EActivity(R.id.main)
public class DetailsActivity extends FragmentActivity {

}

Fragment Support

Since AndroidAnnotations 2.6

AndroidAnnotations supports both android.app.Fragment and android.support.v4.app.Fragment, and automatically uses the right APIs based on the fragment types.

Enhanced Fragments

To start using AndroidAnnotations features in a fragment, annotate it with @EFragment:

@EFragment
public class MyFragment extends Fragment {

}

AndroidAnnotations will generate a fragment subclass with a trailing underscore, e.g. MyFragment_. You should use the generated subclass in your xml layouts and when creating new instance fragments:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/myFragment"
        android:name="com.company.MyFragment_"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

Programmatically:

MyFragment fragment = new MyFragment_();

Or you can use the fluent builder:

MyFragment fragment = MyFragment_.builder().build();

You can now use all kind of annotations in your fragment:

@EFragment
public class MyFragment extends Fragment {
	@Bean
	SomeBean someBean;
	
	@ViewById
	TextView myTextView;

	@App
	MyApplication customApplication;
	
	@SystemService
	ActivityManager activityManager;
	
	@OrmLiteDao(helper = DatabaseHelper.class, model = User.class)
	UserDao userDao;

	@Click
	void myButton() {
	}

	@UiThread
	void uiThread() {

	}

	@AfterInject
	void calledAfterInjection() {
	}
	
	@AfterViews
	void calledAfterViewInjection() {
	}

	@Receiver(actions = "org.androidannotations.ACTION_1")
	protected void onAction1() {

	}
}

View injection and event listener binding will only be based on views contained inside the fragment. Note, however, that it's isn't currently the case for @EBean injected inside fragments: they have access to the activity views.

Fragment Layout

The standard way to associate a view with a fragment is to override onCreateView():

@EFragment
public class MyFragment extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.my_fragment_layout, container, false);
        return view;
    }
}

You can let AndroidAnnotations handle that for you by setting the value param of the @EFragment annotation:

@EFragment(R.layout.my_fragment_layout)
public class MyFragment extends Fragment {
}

If you need to override onCreateView(), e.g. because you need to access savedInstanceState, you can still let AndroidAnnotations handle the layout creation by returning null:

@EFragment(R.layout.my_fragment_layout)
public class MyFragment extends Fragment {
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return null;
    }
}

Forcing layout injection

Since AndroidAnnotations 3.3

We only inject the layout passed as the first annotation parameter if the onCreateView method from the annotated class (or its superclass if the method is not overridden) returns null. This is because we do not want to override your custom non-null View returned from onCreateView. In some cases still that would be the desired behavior: for example if you extend from the ListFragment class, it returns a non-null View from onCreateView, and your layout does not get injected which is passed to the @EFragment annotation. To work around this, we added a boolean forceLayoutInjection annotation parameter, if it is set to true, the injection happens regardless of the return value of the super onCreateView method. It is false by default, so the old behavior takes place if you do not explicitly set forceLayoutInjection to true.

@EFragment(value = R.layout.my_custom_layout, forceLayoutInjection = true)
public class MyFragment extends ListFragment {
  // R.layout.my_custom_layout will be injected
}

Injecting Fragments

You may inject fragments in classes annotated with @EActivity, @EFragment, @EView, @EViewGroup, @EBean, using @FragmentById or @FragmentByTag. If you don't specify any value on the annotation, the field name is used.

We recommend using @FragmentById rather then @FragmentByTag, because no compile time validation is performed for the latter.

Please be aware that @FragmentById and @FragmentByTag can only inject fragments, not create them, so they must already exist in the activity (either by defining them in the layout or by creating them programmatically in onCreate().

You can inject fragments even if they are not annotated with @EFragment.

@EActivity(R.layout.fragments)
public class MyFragmentActivity extends FragmentActivity {
  @FragmentById
  MyFragment myFragment;
	
  @FragmentById(R.id.myFragment)
  MyFragment myFragment2;
	
  @FragmentByTag
  MyFragment myFragmentTag;
	
  @FragmentByTag("myFragmentTag")
  MyFragment myFragmentTag2;
}

Method based injection

Since AndroidAnnotations 4.0.0

@EActivity(R.layout.fragments)
public class MyFragmentActivity extends FragmentActivity {

  @FragmentById
  void setOneFragmentById(MyFragment myFragmentId){
    // do something with myFragmentId
  }
  
   void setMultipleFragmentsById(@FragmentById MyFragment myFragmentId, @FragmentById(R.id.myFragment) MyFragment myFragmentId2){
    // do something with myFragmentId and myFragmentId2
  }

  @FragmentByTag
  void setOneFragmentByTag(MyFragment myFragmentTag){
    // do something with myFragmentTag
  }
  
   void setMultipleFragmentsByTag(@FragmentByTag MyFragment myFragmentTag, @FragmentByTag("myFragmentTag") MyFragment myFragmentTag2){
    // do something with myFragmentTag and myFragmentTag2
  }

}

Note on DialogFragments

Unfortunetaly you cannot create a new Dialog instance in the onCreateDialog() method if you are using @EFragment. You should just call super.onCreateDialog(), then configure the returned Dialog instance. Then you can setup your views in a @AfterViews annotated method. Please read this thread for more information