Подтвердить что ты не робот

IllegalStateException при замене фрагмента

Это небольшое приложение для тестирования 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 |
---------                ----------

В альбомной ориентации активность имеет представление с двумя фрагментами: "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" не был уничтожен после замены. Вероятно, это следствие моего неправильного пути, чтобы попытаться заменить его.

Любая помощь будет действительно оценена.

Спасибо заранее!

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

4b9b3361

Ответ 1

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

Одна проблема, которая обычно возникает при удалении или замене фрагментов, заключается в попытке удалить фрагмент, который был добавлен в макет через 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 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())

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

Ответ 2

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

в событии onClick просто идентифицируйте ориентацию с помощью: getResources(). getConfiguration(). ориентация

и сделайте свой материал