11

Mam działanie, które ładuje listę danych z serwera za pomocą wywołań zwrotnych programu ładującego. Mam do listy zawierającej dane do fragmentu, który rozciągaZatwierdź fragment z onLoadFinished w ramach działania

SherlockListFragment 

próbowałem popełnić fragment używając

Fragment newFragment = CategoryFragment.newInstance(mStackLevel,categoryList); 
FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
ft.add(R.id.simple_fragment, newFragment).commit(); 

w onLoadFinished i daje IllegalStateException mówiąc

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished 

mam odesłał przykład w sherlocku actionbar, ale te przykłady mają ładunki w obrębie fragmentów, a nie aktywność.

Czy ktoś może mi pomóc z tym, że mogę to naprawić bez wywoływania programu ładującego z fragmentu!

+0

możliwe duplikat [Android - problemy z zastosowaniem FragmentActivity + ładowarki aktualizacji FragmentStatePagerAdapter] (http://stackoverflow.com/questions/7746140/android-problems-using-fragmentactivity-loader- to-update-fragmentstatepagera) – rds

Odpowiedz

14

Atlast, znalazłem rozwiązanie tego problemu. Utwórz uchwyt ustawiający pustą wiadomość i wywołaj tę funkcję obsługi naLoadFinished(). Kod jest podobny do tego.

@Override 
public void onLoadFinished(Loader<List<Station>> arg0, List<Station> arg1) { 
    // do other actions 
    handler.sendEmptyMessage(2); 
} 

w uchwycie,

private Handler handler = new Handler() { // handler for commiting fragment after data is loaded 
    @Override 
    public void handleMessage(Message msg) { 
     if(msg.what == 2) { 
      Log.d(TAG, "onload finished : handler called. setting the fragment."); 
      // commit the fragment 
     } 
    } 
}; 

liczba fragmentów zależy od zapotrzebowania.

This method can be mainly used in case of stackFragments, where all fragments have different related functions. 
+1

Hmm, odradzam to. Jeśli naprawdę potrzebujesz ułożyć fragmenty, tak jak mówisz, możesz po prostu zadzwonić do commitAllowingStateLoss(). Pozwoli to uniknąć obsługi i wyjątku IllegalArgumentException, tak jak mówisz na platformie ... "W porządku, jestem świadomy ryzyka. Zrób to tak czy inaczej". Zobacz [link] (https://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html#commitAllowingStateLoss()) – kwazi

+0

Dzięki kwazi, wypróbowałem tę metodę. Dzięki za pomoc. To była dobra rada. Pozdrawiam :) – DroidBee

+4

Tylko uwaga: wywoływanie commitAllowStateLoss nie jest opcją podczas wywoływania DialogFragment.show(). Musiałem użyć programu obsługi dla tego konkretnego typu transakcji fragmentu. – javahead76

8

Jak na Androida Docs na metodzie onLoadFinished():

Zauważ, że normalnie aplikacja nie dopuszcza do popełnienia transakcji fragmencie, gdy w tej rozmowie, ponieważ może się zdarzyć, gdy stan działalność jest zapisana. Zobacz FragmentManager.openTransaction() w celu dalszej dyskusji na ten temat.

https://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished(android.content.Loader, D)

(Uwaga: copy/paste, która odwołuje się do swojej przeglądarce ... StackOverflow nie jest obsługa to dobrze ..)

Więc po prostu nigdy nie powinien wczytać fragment w które stan. Jeśli naprawdę nie chcesz umieścić programu ładującego w Fragmentie, musisz zainicjować fragment w swojej metodzie onCreate() działania, a gdy pojawi się on onLoadFinished, po prostu wywołaj metodę na swoim fragmencie.

Niektóre szorstki kod pseudo następująco:

public class DummyFragment { 

    public void setData(Object someObject) { 
      //do stuff 
    } 

public class DummyActivity extends LoaderCallbacks<Object> { 

    public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 

      Fragment newFragment = DummyFragment.newInstance(); 
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
      ft.add(R.id.simple_fragment, newFragment).commit(); 

      getSupportLoaderManager.initLoader(0, null, this) 
    } 

    // put your other LoaderCallbacks here... onCreateLoader() and onLoaderReset() 

    public void onLoadFinished(Loader<Object> loader, Object result) { 
      Fragment f = getSupportLoaderManager.findFragmentById(R.id.simple_fragment); 
      f.setData(result); 
    } 

Oczywiście, że chcesz użyć odpowiedniego obiektu .. i właściwą ładowarkę i pewnie określić sposób użyteczny setData(), aby zaktualizować fragment . Ale mam nadzieję, że to wskaże ci właściwy kierunek.

+0

Dzięki za odpowiedź! :) Może nie miałem jasności co do mojego pytania. Mam już przygotowany fragment domu, po prostu chciałem zaimplementować układanie kolejnego fragmentu, po załadowaniu niektórych danych. Znalazłem metodę do jej uzupełnienia. Opublikuję to jako odpowiedź. +1 za wsparcie i odpowiedź. Naprawdę nie myślałem o używaniu f.setData (result), które mogłem użyć w tej samej aktywności w innych fragmentach. :) – DroidBee

+0

Ah, nie wiedziałem. W każdym razie zobacz mój komentarz na temat twojej odpowiedzi dotyczącej lepszego rozwiązania. commitAllowingStateLoss() byłby sposobem na ... – kwazi

0

Jak @kwazi odpowiedziało jest to złe doświadczenia użytkownika zadzwonić FragmentTransition.commit() z onLoadFinished(). Znalazłem rozwiązanie dla tego zdarzenia przy użyciu ProgressDialog.

Pierwszy stworzony ProgressDialog.setOnDismissListener(new listener) do oglądania onLoadFinished(). Dalsze zrobić progressDialog.show() przed getLoaderManager().restartLoader(). I ostatecznie umieścić progressDialog.dismiss() w onLoadFinished(). Takie podejście pozwala nie wiązać głównego wątku interfejsu użytkownika i wątku modułu ładującego.

public class FrPersonsListAnswer extends Fragment 
 
\t \t \t \t \t \t implements 
 
\t \t \t \t \t \t LoaderCallbacks<Cursor>{ 
 
private ProgressDialog progressDialog; 
 
           \t @Override 
 
\t public View onCreateView(LayoutInflater inflater, 
 
\t \t \t ViewGroup container, Bundle savedInstanceState) { 
 
\t \t View view = inflater.inflate(R.layout.fragment_persons_list, container, false); 
 
\t \t 
 
\t \t //prepare progress Dialog 
 
\t \t progressDialog = new ProgressDialog(curActivity); 
 
\t \t progressDialog.setMessage("Wait..."); 
 
\t \t progressDialog.setIndeterminate(true); 
 
\t \t progressDialog.setOnDismissListener(new OnDismissListener() { 
 
\t \t \t 
 
\t \t \t @Override 
 
\t \t \t public void onDismiss(DialogInterface dialog) { 
 
\t \t \t \t //make FragmentTransaction.commit() here; 
 
\t \t \t \t 
 
\t \t \t \t //but it's recommended to pass control to your Activity 
 
\t \t \t \t //via an Interface and manage fragments there. 
 
\t \t \t } 
 
\t \t }); 
 
\t \t 
 
\t \t lv = (ListView) view.findViewById(R.id.lv_out1); 
 
\t \t lv.setOnItemClickListener(new OnItemClickListener() { 
 

 
\t \t \t @Override 
 
\t \t \t public void onItemClick(AdapterView<?> parent, final View view, 
 
\t \t \t \t \t final int position, long id) { 
 
\t \t \t \t 
 
\t \t \t \t //START PROGRESS DIALOG HERE 
 
\t \t \t \t progressDialog.show(); 
 
\t \t \t \t 
 
\t \t \t \t Cursor c = (Cursor) parent.getAdapter().getItem(position); 
 

 
\t \t \t \t // create Loader 
 
\t \t \t \t getLoaderManager().restartLoader(1, \t null, curFragment); 
 
\t \t \t } 
 
\t \t }); 
 

 
\t \t return view; 
 
\t } 
 
    
 
\t @Override 
 
\t public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
 
\t \t switch (loader.getId()) { 
 
\t \t case 1: 
 
\t \t \t //dismiss dialog and call progressDialog.onDismiss() listener 
 
\t \t \t progressDialog.dismiss(); 
 
\t \t \t break; 
 

 
\t \t default: 
 
\t \t \t break; 
 
\t \t } 
 
\t }

Powiązane problemy