Невозможно приостановить действие, просмотр содержимого еще не создан

Я взял пример проекта EU4You, продемонстрированный в "Руководстве для CommonsWare по разработке Android 4.2" (любезно предоставлено Марком Мерфи, также известным CommonsWare Stackru). Возможно, будет легче следовать этому примеру проекта, но я постараюсь опубликовать соответствующие части кода в вопросе. Вам также необходимо импортировать проект ActionBarSherlock. Вам также потребуется установить для компилятора Java значение 1.6 (чтобы учесть аннотацию @Override).

ПРИМЕЧАНИЕ: я изменил min-sdk на 8 (2.3, Froyo) и target-sdk на 16 (4.1, Ice Cream Sandwich).

Примечание: я изменил countries идентификатор кадра в left_pane и details идентификатор кадра в right_pane ,

Основной файл макета (макет-большой участок):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <FrameLayout
    android:id="@+id/left_pane"
    android:layout_weight="30"
    android:layout_width="0px"
    android:layout_height="fill_parent"
  />
  <FrameLayout
    android:id="@+id/right_pane"
    android:layout_weight="70"
    android:layout_width="0px"
    android:layout_height="fill_parent"
  />
</LinearLayout>

Основной файл макета:

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

В исходной версии примера приложения есть два действия (точнее SherlockFragmentActivities).

  1. EU4You - загружает соответствующий макет (по умолчанию или большой пейзаж). По умолчанию загружает список стран в SherlockListFragment. Если ландшафт большой, загружается список и фрагмент сведений для отображения выбранной страны.
  2. DetailsActivity - загружает выбранную страну через фрагмент DetailsFragment, когда не используется макет с альбомной ориентацией.

Если вы щелкнете по стране в фрагменте списка, EU4You (основная деятельность хостинга) проверяет наличие и видимость фрагмента DetailsFragment. Если он существует, он загружает сайт страны внутри этого фрагмента. Если нет, он запускает DetailsActivity, которая затем обрабатывает добавление DetailsFragment (который затем загружает веб-сайт для данной страны).

Это прекрасно работает, как обычное приложение, поддерживающее несколько экранов на планшетах и ​​телефонах.

Моя проблема в том, что я хочу удалить DetailsActivity и придерживаться одного действия. Я хочу заменить (заменить) фрагмент списка фрагментом подробностей, когда я не нахожусь в крупном альбомном макете (другими словами, я либо в портретном макете на планшете, либо на телефоне в любой ориентации). Итак, что я сделал, изменил следующее в EU4You SherlockFragmentActivity:

Оригинал (с небольшим изменением имен для имен структуры, упомянутых в примечании далее... страны - left_pane, детали - right_pane):

@Override
public void onCountrySelected(Country c) {
    String url=getString(c.url);

    if (details != null && details.isVisible()) {
        details.loadUrl(url);
    }
    else {
        Intent i=new Intent(this, DetailsActivity.class);

        i.putExtra(DetailsActivity.EXTRA_URL, url);
        startActivity(i);
    }
}

Моя модифицированная одиночная версия активности:

@Override
public void onCountrySelected(Country c) {
    String url=getString(c.url);

    if (details != null && details.isVisible()) {
        details.loadUrl(url);
    } 
    else {
        details = new DetailsFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.left_pane, details);
        ft.addToBackStack(null);
        ft.commit();
        getSupportFragmentManager().executePendingTransactions();
        details.loadUrl(url);
    }
}

Это работает как ожидалось. Я нажимаю на веб-сайт в списке (в портретном режиме на планшете или на телефоне в любой ориентации), и детали отображаются во фрагменте сведений, который заменяет фрагмент списка веб-сайтов. Однако, если я затем нажимаю кнопку "Домой" на устройстве, когда отображаются сведения о стране, я получаю ошибку принудительного закрытия со следующими сведениями logcat (только с макетом по умолчанию, содержащим только одну рамку left_pane… Я не эта проблема не возникает в альбомной ориентации на планшетах, когда есть left_pane и right_pane):

11-16 15:04:33.525: E/AndroidRuntime(688): FATAL EXCEPTION: main
11-16 15:04:33.525: E/AndroidRuntime(688): java.lang.RuntimeException: Unable to pause activity {com.commonsware.android.eu4you/com.commonsware.android.eu4you.EU4You}: java.lang.IllegalStateException: Content view not yet created
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3348)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3305)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3288)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.access$2500(ActivityThread.java:125)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2040)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.os.Handler.dispatchMessage(Handler.java:99)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.os.Looper.loop(Looper.java:123)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.main(ActivityThread.java:4627)
11-16 15:04:33.525: E/AndroidRuntime(688):  at java.lang.reflect.Method.invokeNative(Native Method)
11-16 15:04:33.525: E/AndroidRuntime(688):  at java.lang.reflect.Method.invoke(Method.java:521)
11-16 15:04:33.525: E/AndroidRuntime(688):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
11-16 15:04:33.525: E/AndroidRuntime(688):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
11-16 15:04:33.525: E/AndroidRuntime(688):  at dalvik.system.NativeStart.main(Native Method)
11-16 15:04:33.525: E/AndroidRuntime(688): Caused by: java.lang.IllegalStateException: Content view not yet created
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.ListFragment.getListView(ListFragment.java:222)
11-16 15:04:33.525: E/AndroidRuntime(688):  at com.commonsware.android.eu4you.CountriesFragment.onSaveInstanceState(CountriesFragment.java:64)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.java:1574)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1644)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:499)
11-16 15:04:33.525: E/AndroidRuntime(688):  at com.actionbarsherlock.app.SherlockFragmentActivity.onSaveInstanceState(SherlockFragmentActivity.java:127)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.Activity.performSaveInstanceState(Activity.java:1036)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1180)
11-16 15:04:33.525: E/AndroidRuntime(688):  at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3330)
11-16 15:04:33.525: E/AndroidRuntime(688):  ... 12 more

Я могу остановить эту ошибку, если уберу следующую строку из кода выше:

ft.addToBackStack(null);

Мне действительно нужно иметь возможность добавить транзакцию замены в backstack, поэтому я не могу удалить эту строку (этот пример приложения является основой для моего реального приложения, в котором есть больше материала, но я использовал его для упрощения своей проблемы).

Итак, два вопроса:

  1. Почему это происходит?
  2. Как я могу это исправить (возможно, другой подход)?

Следует отметить, что в моем реальном приложении эта логика должна находиться внутри вкладок в панели действий (ActionBarSherlock, поскольку я должен поддерживать ее до версии 2.3 (Froyo)).


ОБНОВЛЕНИЕ (2012-Nov-22 13:27 EST)

Я разместил пример проекта на GitHub. Я новичок в разработке Eclipse и Android, поэтому, возможно, я не включил все, что мне было нужно (рабочая область не была включена, и я не думаю, что проект ActionBarSherlock включен... его нужно будет импортировать (можно найти здесь)).

1 ответ

Решение

Я не могу комментировать ваш конкретный сбой, так как я не видел этой ошибки, кроме как предположить, что она связана с replace() вместо того, чтобы использовать attach() / detach() (просто предположение).

Тем не мение, getSupportFragmentManager().executePendingTransactions(); для меня это запах кода. Я предполагаю, что вы делаете это в интересах details.loadUrl(url);, Вместо этого, пожалуйста, добавьте элемент данных в DetailsFragment, что-то вроде urlToBeApplied, и имеют loadUrl() спрятать значение там, если WebView еще не существует. Затем он может применить URL в onCreateView(), Поможет ли это в связи с вашей аварией, я не могу сказать.

Возможно, вы захотите опубликовать полный пример проекта, который демонстрирует проблему, поскольку вы рассчитываете на то, что люди распознают сообщение об ошибке.


ОБНОВИТЬ

Основываясь на примере приложения, я смог лучше диагностировать проблему.

Content view not yet created, на ListFragment, будет означать, что мы пытаемся позвонить getListView() для фрагмента, который еще не прошел onCreateView() или прошел onDestroyView(), Это обычно указывает на проблему времени.

В этом случае, как оказалось, работа, которая терпела крах, была излишней, так или иначе. onSaveInstanceState() пытается удерживать позицию проверенного элемента, поэтому мы можем проверить ее позже (например, после изменения конфигурации). Тем не менее, нам даже не нужно быть в проверенном режиме, во-первых, когда мы находимся normal дисплеи. Проверенный режим предназначен для activated состояние, которое уместно, когда список и детали располагаются рядом, но не имеет значения, когда нет. Таким образом, обходной путь заключается в том, чтобы просто не беспокоиться с onSaveInstanceState() логика, если нам не нужен постоянный выбор... который мы можем легко получить, вызвав isPersistentSelection() на нашем listener,

Однако, ради аргумента, давайте представим, что нам нужно было сделать эту работу. В этом случае у нас есть несколько вариантов. Самое простое, вероятно, переопределить onDestroyView() и кэшировать проверенную позицию элемента, используя это в onSaveInstanceState() если getListView() возвращается null,

Другие вопросы по тегам