android.R.id.content as container for Fragment

Ilya Demidov picture Ilya Demidov · Jul 12, 2014 · Viewed 14.8k times · Source

My situation is Activity A which contains Fragment B. I always implement it like this.

Layout for Activity A:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Layout for Fragment B:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_title"
        android:layout_centerInParent="true"
        android:background="@drawable/green_button"
        android:textColor="@android:color/white"/>

</RelativeLayout>

This works great, but if we open Android Device monitor and look at View Hierarchy:

So, I do not like that in my hierarchy there are two same useless FrameLayouts and I can cut my R.id.container. I do it like this:

onCreate(Bundle args) implementation in my Activity A:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getFragmentManager().beginTransaction()
        .add(android.R.id.content, FragmentB.newInstance()).commit();
}

I just do not set content for my Activity and attach my Fragment B to system container android.R.id.content. This works great for me. I removed one useless include.

My question is it good practice to do this "hack". Could it crashs my application in any cases and what problems could I have after this implementation? May be somebody has useful experience in this question?

Thanks to all for good answers.

Answer

Maciej Ciemięga picture Maciej Ciemięga · Jul 12, 2014

there is nothing wrong with it. Like you said: you dont need your extra R.id.content layout so... just don't add it with setContentView. There is even mention about it in official documentation of ActionBar: http://developer.android.com/guide/topics/ui/actionbar.html#Tabs

Alternatively, if the tab content will fill the activity layout, then your activity doesn't need a layout at all (you don't even need to call setContentView()). Instead, you can place each fragment in the default root view, which you can refer to with the android.R.id.content ID

If you develop only for 14+ (because of native ActionBar) everything should be fine with it, but if you use support lib please read the points below.

I. If you use Support Library revision lower than 19:

Important thing is: What is your min API level that you develop for?

If your app supporting API < 14 and you use AppCompat you must be aware the different behavior. android.R.id.content is the part of screen where your application should display it's content. On native API 14+ This is just part below ActionBar, because this part is supposed to display activity content.

In AppCompat, where there is no native support for ActionBar. android.R.id.content is the container of entire app screen. This means - including ActionBar, because ActionBar is emulated there and added as a standard view hierarchy. To solve this issue you have to check whether you are on API lower than 14 and use different id: R.id.action_bar_activity_content


You can create helper method to get correct id:

public static int getContentViewId() {
    return Build.VERSION.SDK_INT>=Build.VERSION_CODES.ICE_CREAM_SANDWICH ? android.R.id.content : R.id.action_bar_activity_content;
}

So if you are developing for 14+ this is perfectly fine solution. If you use custom ActionBar implementation (like AppCompat) you have to do this trick.


II. If you use Support Library revision 19 (or greater):

It seems that this behavior was fixed in Support Library revision 19: https://code.google.com/p/android/issues/detail?id=58108#c21

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/support/v7/app/ActionBarActivityDelegateBase.java/#228

You can see that they replacing the old R.id.action_bar_activity_content with standard android.R.id.content (and the old android.R.id.content with NO_ID) for better compatibility! So if you use Support Lib r19 or greater (or just a native framework) you can just just android.R.id.content in both <14 and 14+ variants:)