IllegalStateException при замене фрагмента - PullRequest
44 голосов
/ 10 октября 2011

Это небольшое тестовое приложение для Android 2.2, использующее пакет совместимости. Это (конечно, неправильно) способ, которым я пытаюсь заменить фрагмент при получении клика. Я пытаюсь заменить его новым (другим) экземпляром того же класса Fragment. Как я объясню, это не работает, как ожидалось, и мне нужна помощь:

public class MainFragmentActivity extends FragmentActivity {
  ...

  public void myAction(View view) {
    ...
    RightFragment newRightFrag = RightFragment.newInstance(myNewOption);
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
    ft.replace(R.id.landscape_right_fragment, newRightFrag);
    ft.commit();
  }
}

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

Пейзаж Ориентация:

---------                ----------
| L | R |  -> click ->   | L | R2 |
---------                ----------

В альбомной ориентации вид деятельности имеет 2 фрагмента: « leftLand » & « rightLand » и при нажатии кнопки фрагмента « leftLand", затем он изменяется, создает новый фрагмент и заменяет экземпляр фрагмента" rightLand"другим экземпляром того же класса FragamentActivity. Что отличает эти два экземпляра, так это параметр, передаваемый в "newInstance (int)", он основан на нажатой кнопке.

Портретная ориентация:

-----                  -----
|   |                  |   |
| L |   -> click ->    | R |
|   |                  |   |
-----                  -----

В портретной ориентации он просто показывает фрагмент " leftPort " (имеет ту же компоновку, что и " leftLand "), и если вы нажмете на его кнопку, то запустит Intent и запустит RightFragmentActivity, которое показывает фрагмент " rightLand "

Работает нормально ... если я не заменю нужный фрагмент. Если я это сделаю (нажав кнопку в альбомной ориентации), то при последующем изменении ориентации (перезапуске действия) FragmentActivity не сможет запуститься из-за "IllegalStateException: Fragment RightFragment did not create a view" , подобного этому:

D/AndroidRuntime( 1428): Shutting down VM
W/dalvikvm( 1428): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
E/AndroidRuntime( 1428): FATAL EXCEPTION: main
E/AndroidRuntime( 1428): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.agm.test/com.agm.test.MainFragmentActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
E/AndroidRuntime( 1428):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.access$2400(ActivityThread.java:125)
E/AndroidRuntime( 1428):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
E/AndroidRuntime( 1428):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 1428):        at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.main(ActivityThread.java:4627)
E/AndroidRuntime( 1428):        at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 1428):        at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 1428):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime( 1428):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
E/AndroidRuntime( 1428):        at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 1428): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
E/AndroidRuntime( 1428):        at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198)
E/AndroidRuntime( 1428):        at android.app.Activity.setContentView(Activity.java:1647)
E/AndroidRuntime( 1428):        at com.agm.test.MainFragmentActivity.onCreate(MainFragmentActivity.java:25)
E/AndroidRuntime( 1428):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
E/AndroidRuntime( 1428):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
E/AndroidRuntime( 1428):        ... 12 more
E/AndroidRuntime( 1428): Caused by: java.lang.IllegalStateException: Fragment com.agm.test.RightFragment did not create a view.
E/AndroidRuntime( 1428):        at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:287)
E/AndroidRuntime( 1428):        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
E/AndroidRuntime( 1428):        ... 21 more
W/ActivityManager(   59):   Force finishing activity com.agm.test/.MainFragmentActivity

Я понял, что старый " RightFragment " не будет уничтожен после замены. Это, вероятно, является следствием моего неправильного способа попытаться заменить его.

Любая помощь будет очень признательна.

Заранее спасибо!

/ Ангел Галиндо Муньос

Ответы [ 2 ]

94 голосов
/ 10 октября 2011

Я думаю, вы, возможно, неправильно поняли мой комментарий, поэтому я предложу более подробное объяснение здесь.

Одна проблема, которая обычно возникает при удалении или замене фрагментов, - это попытка удалить фрагмент, который был добавлен в макет через XML, а не программно в Java. Это , а не - это то же самое, что раздувать собственный макет фрагмента в функции onCreateView() Java-кода фрагмента (это то, что вы, похоже, описываете в своем ответе на мой комментарий). Чтобы проиллюстрировать, о чем я говорю, я покажу вам два способа, которыми люди пытаются удалить / заменить фрагменты.

Это неправильный способ сделать это:

XML-формат:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <fragment android:name="com.example.ExampleFragment"
    android:id="@+id/example_fragment"
    android:layout_weight="1"
    android:layout_width="0dp"
    android:layout_height="match_parent" />

</LinearLayout>

Java

swapFragment()
{
    Fragment newFragment = new ExampleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

Этот код не будет выполняться так, как вы ожидаете. Исходный фрагмент, добавленный в макет XML, не будет удален. Это потому, что макеты XML предназначены для описания статических элементов макета. Вы можете изменить их содержимое во время выполнения или скрыть их, но вы не можете удалить их из макета. Это то, о чем говорила Дайана Хэкборн в ветке обсуждения , с которой я связывался ранее.

Это правильный способ сделать это (по крайней мере, по моему опыту):

XML-макет:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

    <!-- Fragment will go here eventually, but it's not added in the layout -->

</LinearLayout>

Java

protected void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);
     setContentView(R.layout.my_layout);

     ExampleFragment newFragment = new ExampleFragment();
     FragmentTransaction transaction = getFragmentManager().beginTransaction();
     transaction.add(R.id.fragment_container, newFragment);
     transaction.commit();
}

...

swapFragment()
{
    Fragment newFragment = new ExampleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    transaction.commit();
}

Эта стратегия не добавляет фрагмент в первоначальный макет. Вместо этого он добавляет его в код Java при создании Activity. Это позволяет удалить его из макета (используя remove() или replace())

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

0 голосов
/ 19 ноября 2013

есть и другой способ, когда вы разрабатываете приложения для планшетов с большими экранами, вы можете раздувать разную компоновку для каждой ориентации экрана. Вам просто нужно создать две раскладки и присвоить им имена в портретной или альбомной ориентации, в onCreate это просто надуть xml в соответствии с ориентацией.

в событии onClick просто определите ориентацию с помощью: getResources (). GetConfiguration (). Ориентация

и делай свое дело

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...