3

Ich habe ein Problem mit EventBus von Greenrobot.Wie Sie eine Nachricht von einem Hintergrunddienst an ein UI-Fragment senden?

Ich habe versucht, ein Ereignis von einem Hintergrunddienstformular mein Sync-Adapter zu buchen und es in einem Fragment abzufangen, um die Benutzeroberfläche zu aktualisieren.

Das Problem ist, dass, wenn ich versuche, das Ereignis von Sync-Adapter zu schreiben ich habe folgend im Debug-Protokoll:

 
No subscribers registered for event class olexiimuraviov.ua.simplerssreader.event.UpdateUIEvent 
No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent 

I registriere Fragment in onResume und deregistrieren es in

@Override 
public void onResume() { 
    super.onResume(); 
    EventBus.getDefault().register(this); 
    if (mDebug) Log.d(LOG_TAG, EventBus.getDefault().isRegistered(this) + ""); 
} 

@Override 
public void onPause() { 
    super.onPause(); 
    EventBus.getDefault().unregister(this); 
} 

Log-Anweisung in onResume zeigt, dass das Fragment erfolgreich registriert wurde. Hier

ist onEvent Methode:

@Subscribe 
public void onEvent(UpdateUIEvent event) { 
    if (mSwipeRefreshLayout.isRefreshing()) 
     mSwipeRefreshLayout.setRefreshing(false); 
} 

Ich versuchte Methode aufzurufen onEvent mit Hintergrund threadmode aber es half nicht.

Danach habe ich versucht, Handler zu verwenden, um Ereignis zu buchen, aber Eventbus kann immer noch keine registrierten Abonnenten für Ereignis finden.

new Handler(Looper.getMainLooper()).post(new Runnable() { 
    @Override 
    public void run() { 
     EventBus.getDefault().post(new UpdateUIEvent()); 
    } 
}); 

Hier ist meine onPerform Methode der Sync-Adapter:

@Override 
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { 
    // Fetch data from server 
    } finally { 
     // close everything 
     new Handler(Looper.getMainLooper()).post(new Runnable() { 
      @Override 
      public void run() { 
       Log.d(LOG_TAG, "Update event"); 
       EventBus.getDefault().post(new UpdateUIEvent()); 
      } 
     }); 
    } 
} 

Wie kann ich EventBus Ereignis von einem Sync-Adapter an ein Fragment mit Greenrobot schicken?

+0

Versuchen Sie Ihre Event-Handler von onEvent zu onEventMainThread ändern. Hast du überprüft, ob dein Fragment onPause durchgelaufen ist? – Francesc

+0

Ich habe versucht, Methodenname zu ändern und auch versucht, threadmode MAIN Annotation hinzufügen, aber es hat nicht geholfen. Ja, ich habe es überprüft. @Francesc –

+0

Also ist dein Fragment pausiert? Es wird offensichtlich nichts empfangen können, wenn es onPause durchlaufen hat. – Francesc

Antwort

5

tl; dr

Sie haben nie über die Thread Sie ein Ereignis hinzufügen von Sorgen zu machen, aber Sie haben über die Prozess kümmern Sie es aus posten. Ihr Synchronisierungsadapter wird in einem anderen Prozess als Ihr Fragment ausgeführt - der EventBus funktioniert nur innerhalb des Prozesses, in dem er erstellt wurde.

Long Version

Sie müssen nie verschiedene Threads drehen oder sogar zu befürchten, welchen Thread sind Sie an jedem Ort, außer in dem Sie für das Ereignis abonnieren.

Check http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/ für mehr Details, aber die Syntax ist sehr selbsterklärend:

@Subscribe(threadMode = ThreadMode.BACKGROUND) 
public void thisMethodWillBeRunInABackgroundThread(DoLoginEvent event) 
{ 
    //Run some code that makes an HTTP request 
} 

Und etwas auf der Benutzeroberfläche auszuführen:

@Subscribe(threadMode = ThreadMode.MAIN) 
public void thisMethodWillBeRunOnTheUIThread(LoginSuccessfulEvent event) 
{ 
    //Run some code that touches the UI 
} 

Wenn Sie post() rufen beide abzufeuern die DoLoginEvent und die LoginSuccessfulEvent es ist absolut egal, in welchem ​​Thread Sie sind.

Nun zu dem echten Problem, das Sie haben: Ereignis s scheinen nicht auf den abonnierenden Objekten erfasst zu sein.

Ich vermute, dass dies daran liegt, dass Ihr Sync-Adapter in einem anderen Prozess läuft. Der EventBus funktioniert nur innerhalb des Prozess es ist erstellt.

Ein Synchronisationsadapter, wie ein BroadcastReceiver oder ein Dienst, wird in einem separaten Prozess ausgeführt, damit Sie Daten mit Ihrem Server ohne beliebige Interaktion mit Ihrer App selbst synchronisieren können. Die Idee ist, dass Sie mit dem Server synchronisieren, während die App geschlossen ist, und alles in einer Datenbank speichern. Wenn die App gestartet wird, überprüft sie diese Datenbank (schnell), anstatt mit dem Server synchronisiert zu werden (langsam). Aber wenn Ihre Anwendung aktiv ist, wenn der Synchronisierungsadapter ausgeführt wird, möchten Sie in der Datenbank speichern, aber auch der App mitteilen, dass einige neue Informationen richtig sind?

Damit Ihr Sync-Adapter mit Ihrer Anwendung kommunizieren kann, rate ich Ihnen, einen BroadcastReceiver in Ihrem Fragment/Ihrer Aktivität einzurichten und dann eine Absicht von Ihrem Sync-Adapter zu senden.

Dieser Mechanismus ist ein sehr ähnliches Konzept wie der EventBus, Sie können sogar senden sticky intents! Dein Fragment hört auf diese Absichten, aber nur solange es lebt. Wenn Ihr Synchronisierungsadapter eine Übertragung sendet, während Ihre Anwendung geschlossen ist, passiert nichts. Aber wenn das Fragment startet und für diese Absichten registriert, wird es die letzte sticky eins.

public class LogFragment extends Fragment { 

    private LogReceiver mReceiver; 

    public class LogReceiver extends BroadcastReceiver { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      //you can call the EventBus from in here 
     } 
    } 


    @Override 
    public void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     mReceiver = new LogReceiver(); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     getActivity().registerReceiver(mReceiver, new IntentFilter("com.whatever.whatever")); 
     return view; 
    } 

    @Override 
    public void onDestroyView() { 
     getActivity().unregisterReceiver(mReceiver); 
     super.onDestroy(); 
    } 
} 

Und dann von Ihrem Sync-Adapter

Intent sendIntent = new Intent("com.whatever.whatever"); 
sendIntent.putExtra("SYNC_ADAPTER_EXTRA", "Your sync adapter says hi"); 
context.sendBroadcast(sendIntent); 
+0

Your'e right! Danke für Ihre Hilfe! –

+0

Sie sind herzlich willkommen! – shredder