11

Ich habe eine Aktivität, die eine Datenliste vom Server mit Loader Callbacks lädt. Ich habe, um die Daten in ein Fragment auflisten, dieCommit-Fragment von onLoadFinished innerhalb der Aktivität

SherlockListFragment 

i erstreckt versucht, das Fragment zu begehen

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

in onLoadFinished verwenden und es gibt eine Illegal sagen

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

Ich habe verwiesen das Beispiel in actionbar sherlock, aber diese Beispiele haben Loader innerhalb der Fragmente und nicht die Aktivität.

Kann mir jemand dabei helfen, dass ich es beheben kann, ohne den Loader aus dem Fragment zu rufen!

+0

möglich Duplikat [Android - Probleme FragmentActivity + Loader FragmentStatePagerAdapter aktualisieren] (http://stackoverflow.com/questions/7746140/android-problems-using-fragmentactivity-loader- to-update-fragmentstatepagera) – rds

Antwort

14

Atlast, ich habe eine Lösung für dieses Problem gefunden. Erstellen Sie ein Handle, das eine leere Nachricht festlegt, und rufen Sie den Handler onLoadFinished() auf. Der Code ist ähnlich.

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

Im Handler hängen

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 
     } 
    } 
}; 

Die Anzahl der Fragmente auf der Anforderung.

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

Hmm würde ich davon abraten. Wenn Sie wirklich Fragmente stapeln müssen, wie Sie sagen, dann könnten Sie einfach commitAllowingStateLoss() aufrufen. Dies wird den Handler und die IllegalArgumentException vermeiden, wie Sie der Plattform sagen würden. "Es ist in Ordnung, ich bin mir der Risiken bewusst ... mach es trotzdem". Siehe [link] (https://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html#commitAllowingStateLoss()) – kwazi

+0

Danke kwazi, ich habe diese Methode ausprobiert. Danke für Ihre Hilfe. Das war ein guter Ratschlag. Prost :) – DroidBee

+4

Nur eine Anmerkung: Aufruf commitAllowStateLoss ist keine Option beim Aufrufen von DialogFragment.show(). Ich musste einen Handler für diese bestimmte Art von Fragmenttransaktion verwenden. – javahead76

8

sich nach den Android docs auf der onLoadFinished() -Methode:

Beachten Sie, dass normalerweise eine Anwendung ist nicht erlaubt Fragment Transaktionen während in diesem Aufruf zu begehen, da er nach einer Tätigkeit des Staates gerettet wird passieren kann. Weitere Informationen hierzu finden Sie unter FragmentManager.openTransaction().

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

(Hinweis: Kopieren/Einfügen, die in Ihrem Browser Link ... Stackoverflow ist es nicht gut Handhabung ..)

Deshalb sollte man einfach nie ein Fragment, dass laden Zustand. Wenn Sie den Loader wirklich nicht in das Fragment einfügen möchten, müssen Sie das Fragment in Ihrer onCreate() -Methode der Aktivität initialisieren, und wenn onLoadFinished auftritt, rufen Sie einfach eine Methode für Ihr Fragment auf.

Einige grobe Pseudo-Code folgt:

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); 
    } 

Offensichtlich würden Sie wollen das richtige Objekt verwenden .. und das richtige Ladeprogramm und wahrscheinlich auch eine nützliche Methode setData() definieren Sie Ihre Fragment zu aktualisieren . Aber das wird hoffentlich in die richtige Richtung weisen.

+0

Danke für deine Antwort! :) Vielleicht war ich nicht klar über meine Frage. Ich habe bereits mein Homefragment entwickelt, wollte nur das Stapeln des nächsten Fragments implementieren und einige Daten laden. Ich habe eine Methode gefunden, das zu implementieren. Ich werde es als Antwort posten. +1 für Ihre Unterstützung und Antwort. Ich habe wirklich nicht daran gedacht, f.setData (result) zu verwenden, das ich in anderen Fragmenten in derselben Aktivität hätte verwenden können. :) – DroidBee

+0

Ah, das war mir nicht bewusst. Jedenfalls sehe ich meinen Kommentar zu Ihrer Antwort bezüglich einer besseren Lösung. commitAllowingStateLoss() wäre der Weg zu gehen ... – kwazi

0

Als @kwazi beantwortet dies eine schlechte Benutzererfahrung ist FragmentTransition.commit() von onLoadFinished() zu nennen. Ich habe mit ProgressDialog eine Lösung für dieses Ereignis gefunden.

erstellt Erste ProgressDialog.setOnDismissListener(new listener) für das Ansehen der onLoadFinished(). Weitere i progressDialog.show() tun, bevor getLoaderManager().restartLoader(). Und schließlich Platz progressDialog.dismiss() in onLoadFinished(). Ein solcher Ansatz erlaubt es nicht, den Haupt-UI-Thread und den Loader-Thread zu binden.

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 }