Android.R.id.content как контейнер для фрагмента

Моей ситуацией является Activity A, которая содержит фрагмент B. Я всегда реализую его так.

Макет для действия 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" />

Макет для фрагмента 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>

Это отлично работает, но если мы откроем монитор Android-устройств и посмотрим на View Hierarchy:

Итак, мне не нравится, что в моей иерархии есть два одинаковых бесполезных FrameLayouts, и я могу сократить свой файл R.id.container. Я делаю это так:

onCreate (Bundle args) реализация в моей деятельности A:

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

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

Я просто не устанавливаю контент для своей активности и прикрепляю свой фрагмент B к системному контейнеру android.R.id.content. Это отлично работает для меня. Я удалил один бесполезный include.

Мой вопрос - это хорошая практика сделать это "взломать". Может ли это привести к сбою моего приложения в любом случае и какие проблемы могут возникнуть после этой реализации? Может быть, у кого-нибудь есть полезный опыт в этом вопросе?

Спасибо всем за хорошие ответы.

Ответы

Ответ 1

в этом нет ничего плохого. Как вы сказали: вам не нужен ваш дополнительный макет R.id.content, поэтому... просто не добавляйте его с помощью setContentView. Об этом даже упоминается в официальной документации ActionBar: http://developer.android.com/guide/topics/ui/actionbar.html#Tabs

В качестве альтернативы, если содержимое вкладки заполнит макет действия, тогда вашей деятельности не требуется макет вообще (вам даже не нужно вызовите setContentView()). Вместо этого вы можете поместить каждый фрагмент в по умолчанию, который вы можете ссылаться на android.R.id.content ID

Если вы разрабатываете только 14+ (из-за родного ActionBar), все должно быть хорошо с ним, но если вы используете поддержку lib, пожалуйста, прочитайте приведенные ниже пункты.

I. Если вы используете версию библиотеки поддержки ниже 19:

Важно следующее: Каков ваш минимальный уровень API, для которого вы разрабатываете?

Если ваше приложение поддерживает API < 14, и вы используете AppCompat, вы должны знать о разных поведении. android.R.id.content является частью экрана, на котором ваше приложение должно отображать его содержимое. На native API 14+ Это всего лишь часть ниже ActionBar, потому что эта часть должна отображать содержимое активности.

В AppCompat, где нет активной поддержки ActionBar. android.R.id.content - это контейнер всего экрана приложения. Это означает - в том числе ActionBar, потому что ActionBar эмулируется там и добавляется как стандартная иерархия представлений. Чтобы решить эту проблему, вы должны проверить, находитесь ли вы в API ниже 14 и используете разные идентификаторы: R.id.action_bar_activity_content


Вы можете создать вспомогательный метод для получения правильного 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;
}

Итак, если вы разрабатываете 14+, это идеальное решение. Если вы используете пользовательскую реализацию ActionBar (например, AppCompat), вам нужно сделать этот трюк.


II. Если вы используете версию 19 технической поддержки (или больше):

Похоже, что это поведение было исправлено в версии 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

Вы можете видеть, что они заменяют старый R.id.action_bar_activity_content на стандартный android.R.id.content (и старый android.R.id.content с NO_ID) для лучшей совместимости! Поэтому, если вы используете поддержку Lib r19 или больше (или только родную фреймворку), вы можете просто просто android.R.id.content в обоих вариантах: < 14 и 14+:)