2013-11-18 2 views
7

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

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

После fragA был добавлен в основной раскладке, я называю публичный метод fragA.addFragB(), чтобы получить его, чтобы добавить экземпляр FragmentClassB к себе, но это приводит к тому, тестовое приложение к сбою, указывая на «активность была уничтожена» (см LogCat в конце сообщения). Означает ли это, что fragA был уничтожен, поэтому я не могу добавить fragB, или это значит, что fragB был уничтожен, поэтому я не могу добавить его в fragA? Или это совсем другое?

MainActivity.java

public class MainActivity extends FragmentActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     FragmentManager fragMan = getSupportFragmentManager(); 

     // add Fragment A to the main linear layout 
     FragmentTransaction fragTrans = fragMan.beginTransaction(); 
     FragmentClassA fragA = new FragmentClassA(); 
     fragTrans.add(R.id.mainLinearLayout, fragA); 
     fragTrans.addToBackStack("A"); 
     fragTrans.commit(); 

     // get Fragment A to add a Fragment B to itself 
     fragA.addFragB(); 
    } 

} 

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context=".MainActivity" > 

    <LinearLayout 
     android:id="@+id/mainLinearLayout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:orientation="horizontal" > 
    </LinearLayout> 

</RelativeLayout> 

FragmentClassA.java

public class FragmentClassA extends Fragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_a, container, false); 
    } 

    public void addFragB() { 
     FragmentManager childFragMan = getChildFragmentManager(); 

     FragmentTransaction childFragTrans = childFragMan.beginTransaction(); 
     FragmentClassB fragB = new FragmentClassB(); 
     childFragTrans.add(R.id.fragA_LinearLayout, fragB); 
     childFragTrans.addToBackStack("B"); 
     childFragTrans.commit(); 

    } 
} 

fragment_a.xml

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


</LinearLayout> 

FragmentClassB.java

public class FragmentClassB extends Fragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_b, container, false); 
    } 

} 

fragment_b.xml

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

    <Button 
     android:id="@+id/button1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button" /> 

</LinearLayout> 

LogCat

11-18 16:17:05.627: E/AndroidRuntime(14351): FATAL EXCEPTION: main 
11-18 16:17:05.627: E/AndroidRuntime(14351): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.nestedfragmenttest/com.example.nestedfragmenttest.MainActivity}: java.lang.IllegalStateException: Activity has been destroyed 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread.access$600(ActivityThread.java:141) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.os.Handler.dispatchMessage(Handler.java:99) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.os.Looper.loop(Looper.java:137) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread.main(ActivityThread.java:5103) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at java.lang.reflect.Method.invokeNative(Native Method) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at java.lang.reflect.Method.invoke(Method.java:525) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at dalvik.system.NativeStart.main(Native Method) 
11-18 16:17:05.627: E/AndroidRuntime(14351): Caused by: java.lang.IllegalStateException: Activity has been destroyed 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1365) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at com.example.nestedfragmenttest.FragmentClassA.addFragB(FragmentClassA.java:26) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at com.example.nestedfragmenttest.MainActivity.onCreate(MainActivity.java:25) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.Activity.performCreate(Activity.java:5133) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 
11-18 16:17:05.627: E/AndroidRuntime(14351): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175) 
11-18 16:17:05.627: E/AndroidRuntime(14351): ... 11 more 

EDIT: ответ

ianhanniballake и позже ответ GrIsHu, который расширяется в той же точке оба были полезны в указании корень проблемы. Однако это вызывает еще одну проблему.
Окончательная цель состоит в том, что FragmentClassA будет частью библиотеки. Он будет использоваться в нескольких ситуациях, и количество экземпляров FragmentClassB будет варьироваться, или их может даже не быть. Следовательно, мне нужно иметь возможность инициировать добавление дочерних фрагментов в любой экземпляр FragmentClassA из родительской активности. Я только что посмотрел на сохранение fragA в качестве переменной уровня класса в MainActivity, а затем вызвал fragA.AddFragB() в методе MainActivityonActivityCreated(), но он недоступен для переопределения. Есть предположения?

+0

Проверьте мой ответ. – GrIsHu

ответ

7

Вы не можете напрямую загрузить фрагмент, который вы указали в FragA. Сначала загружается FragmentA, а затем после того, как вы сможете загрузить FragmentB, вызвав метод addFragB() из вашего метода fragA'sonCreateView().

Попробуйте, как показано ниже:

Удалите строку fragA.addFragB(); из вашего MainActivity

public class MainActivity extends FragmentActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     FragmentManager fragMan = getSupportFragmentManager(); 

     // add Fragment A to the main linear layout 
     FragmentTransaction fragTrans = fragMan.beginTransaction(); 
     FragmentClassA fragA = new FragmentClassA(); 
     fragTrans.add(R.id.mainLinearLayout, fragA); 
     fragTrans.addToBackStack("A"); 
     fragTrans.commit(); 

    } 

} 

И попробуйте загрузить FragmentB из FragmentA, как показано ниже:

public class FragmentClassA extends Fragment { 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     addFragB(); //Call and load fragment B here. 
     return inflater.inflate(R.layout.fragment_a, container, false); 
    } 

    public void addFragB() { 
     FragmentManager childFragMan = getChildFragmentManager(); 

     FragmentTransaction childFragTrans = childFragMan.beginTransaction(); 
     FragmentClassB fragB = new FragmentClassB(); 
     childFragTrans.add(R.id.fragA_LinearLayout, fragB); 
     childFragTrans.addToBackStack("B"); 
     childFragTrans.commit(); 

    } 
} 
+0

Это было полезно. Благодарю. Пожалуйста, проверьте мой вопрос «Редактировать». –

+0

Ну, вещь, которую вы хотите реализовать, является сложной и недействительной для реализации. Можете ли вы сказать мне, в какой библиотеке будет находиться ваш класс 'FragmentA'? – GrIsHu

+0

Чтобы уточнить, FragmentA будет частью проекта Android Library. Он должен функционировать аналогично линейке инструментов, например, в графических редакторах, текстовых процессорах и т. Д. Содержимое паллет инструмента зависит от того, что логично для типа файла, открытого в приложении. Я думал, что переход к Nested Fragments может быть весьма удобным для повторной установки этих поддонов инструмента по мере необходимости. Но из-за этого я, вероятно, должен придерживаться своего старого метода построения паллет инструментов из пользовательских сложных виджетов, а не из дочерних фрагментов. Это то, что вы говорите? –

2

FragmentTransaction.commit не является непосредственным действием согласно the documentation поэтому ваш fragA не привязан к деятельности (следовательно, почему она возвращается, что активность уничтожается) при вызове fragA.addFragB().

Вы должны позвонить addFragB() в FragmentClassA.onCreate(), чтобы гарантировать, что fragA прикреплен к действию и готов к инициализации своего собственного состояния.

+0

Это было полезно. Благодарю. Пожалуйста, проверьте мой вопрос «Редактировать». –

0

Пробовали ли вы добавление этого к фрагментам ребенка:

@Override 
    public void onDetach() { 
     super.onDetach(); 

     try { 
      Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager"); 
      childFragmentManager.setAccessible(true); 
      childFragmentManager.set(this, null); 

     } catch (NoSuchFieldException e) { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) { 
      throw new RuntimeException(e); 
     } 
    } 

это позволит избежать проблем во время переключения между различными фрагментами.

Предположим, что у вас есть активность с фрагментом, который, в свою очередь, имеет два дочерних фрагмента: fragA и FragB.

Вы можете реализовать ребенка фрагменты что-то вроде этого:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
         Bundle savedInstanceState) { 
    View root = inflater.inflate(R.layout.activity_mymessages, container, false); 
    FragmentManager manager = getChildFragmentManager(); 
    FragmentTransaction ft = manager.beginTransaction(); 
    ft.replace(R.id.headlines, fragA); 
    ft.replace(R.id.article, fragB); 
    ft.commit(); 

    return root; 
} 

activity_mymessages.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:gravity="center_horizontal"> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:orientation="horizontal"> 
     <FrameLayout android:id="@+id/headlines" 
      android:layout_height="match_parent" 
      android:name="com.example.fragA" 
      android:layout_width="103dp" 
      android:layout_marginRight="10dp"/> 
     <FrameLayout android:id="@+id/article" 
      android:layout_height="fill_parent" 
      android:name="com.example.fragB" 
      android:layout_width="fill_parent" /> 
    </LinearLayout> 

</FrameLayout> 

Позвольте мне знать, если это работает, если я не могу предоставить рабочий код из моего GitHub.

Смежные вопросы