Android-Äquivalent zu NSNotificationCenter

Lesezeit: 9 Minuten

Benutzer-Avatar
John

Bei der Portierung einer iPhone-Anwendung auf Android suche ich nach der besten Möglichkeit, innerhalb der App zu kommunizieren. Absichten scheinen der richtige Weg zu sein, ist dies die beste (einzige) Option? NSUserDefaults scheint sowohl in der Leistung als auch in der Codierung viel leichter zu sein als Intents.

Ich sollte auch hinzufügen, dass ich eine Anwendungsunterklasse für den Zustand habe, aber ich muss eine andere Aktivität auf ein Ereignis aufmerksam machen.

  • Für Neueinsteiger in dieses Thema ist die zweite Antwort die beste. Runterscrollen…

    – Stefan

    27. Juli 2015 um 12:15 Uhr

Benutzer-Avatar
Schiki

Das beste Äquivalent, das ich gefunden habe, ist LocalBroadcastManager was Teil der ist Android-Supportpaket.

Aus der LocalBroadcastManager-Dokumentation:

Helfer zum Registrieren und Senden von Broadcasts von Intents an lokale Objekte innerhalb Ihres Prozesses. Dies hat eine Reihe von Vorteilen gegenüber dem Senden globaler Broadcasts mit sendBroadcast(Intent):

  • Sie wissen, dass die von Ihnen übertragenen Daten Ihre App nicht verlassen, also brauchen Sie sich keine Sorgen zu machen, dass private Daten preisgegeben werden.
  • Andere Anwendungen können diese Broadcasts nicht an Ihre App senden, sodass Sie sich keine Sorgen über Sicherheitslücken machen müssen, die sie ausnutzen können.
  • Dies ist effizienter als das Senden einer globalen Rundsendung durch das System.

Wenn Sie dies verwenden, können Sie das sagen Intent ist ein Äquivalent zu einem NSNotification. Hier ist ein Beispiel:

ReceiverActivity.java

Eine Aktivität, die nach Benachrichtigungen für das genannte Ereignis sucht "custom-event-name".

@Override
public void onCreate(Bundle savedInstanceState) {

  ...
  
  // Register to receive messages.
  // This is just like [[NSNotificationCenter defaultCenter] addObserver:...]
  // We are registering an observer (mMessageReceiver) to receive Intents
  // with actions named "custom-event-name".
  LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
      new IntentFilter("custom-event-name"));
}

// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    // Get extra data included in the Intent
    String message = intent.getStringExtra("message");
    Log.d("receiver", "Got message: " + message);
  }
};

@Override
protected void onDestroy() {
  // Unregister since the activity is about to be closed.
  // This is somewhat like [[NSNotificationCenter defaultCenter] removeObserver:name:object:] 
  LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
  super.onDestroy();
}

SenderActivity.java

Die zweite Aktivität, die Benachrichtigungen sendet/sendet.

@Override
public void onCreate(Bundle savedInstanceState) {
  
  ...
  
  // Every time a button is clicked, we want to broadcast a notification.
  findViewById(R.id.button_send).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
      sendMessage();
    }
  });
}

// Send an Intent with an action named "custom-event-name". The Intent sent should 
// be received by the ReceiverActivity.
private void sendMessage() {
  Log.d("sender", "Broadcasting message");
  Intent intent = new Intent("custom-event-name");
  // You can also include some extra data.
  intent.putExtra("message", "This is my message!");
  LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}

Mit dem obigen Code jedes Mal die Taste R.id.button_send angeklickt wird, wird ein Intent gesendet und empfangen mMessageReceiver in ReceiverActivity.

Die Debug-Ausgabe sollte wie folgt aussehen:

01-16 10:35:42.413: D/sender(356): Broadcasting message
01-16 10:35:42.421: D/receiver(356): Got message: This is my message! 

  • Vielen Dank, dass Sie sich die Zeit genommen haben, eine so hilfreiche und ausführliche Antwort zu schreiben.

    – Chris Lacy

    5. Februar 2012 um 2:24 Uhr

  • Sie sollten registerReceiver wahrscheinlich nicht in Ihrer onCreate-Methode aufrufen, da dies Ihre Aktivität durchsickern lässt und Ihre onDestroy-Methode niemals aufgerufen wird. onResume scheint eine bessere Wahl zu sein, um registerReceiver aufzurufen, und onPause, um unregisterReceiver aufzurufen.

    – Stéphane JAIS

    23. April 2013 um 9:03 Uhr


  • Perfektes Äquivalent zu NSNotificationCentersollte die akzeptierte Antwort sein!

    – Leon-Story

    14. Oktober 2013 um 23:10 Uhr

  • Ich möchte darauf hinweisen, dass die Verwendung globaler Benachrichtigungen zu einem durcheinandergebrachten Design führen kann. Denken Sie darüber nach, was die beste Verbindung zwischen Ihren Komponenten wäre, bevor Sie zum einfachen Weg springen. Manchmal ist es einfach besser, Listener oder etwas Ähnliches wie das iOS-Delegatmuster usw. zu verwenden.

    – Pedro Andrade

    20. Januar 2014 um 21:31 Uhr


  • Danke das hat bei mir funktioniert. @Shiki, glaubst du, du könntest mir deine Meinung zu dieser Frage sagen? stackoverflow.com/questions/25598696/…

    – Axel

    2. September 2014 um 3:59 Uhr

Hier ist etwas Ähnliches wie die @Shiki-Antwort, aber aus der Sicht der iOS-Entwickler und des Benachrichtigungszentrums.

Erstellen Sie zuerst eine Art NotificationCenter-Dienst:

public class NotificationCenter {

 public static void addObserver(Context context, NotificationType notification, BroadcastReceiver responseHandler) {
    LocalBroadcastManager.getInstance(context).registerReceiver(responseHandler, new IntentFilter(notification.name()));
 }

 public static void removeObserver(Context context, BroadcastReceiver responseHandler) {
    LocalBroadcastManager.getInstance(context).unregisterReceiver(responseHandler);
 }

 public static void postNotification(Context context, NotificationType notification, HashMap<String, String> params) {
    Intent intent = new Intent(notification.name());
    // insert parameters if needed
    for(Map.Entry<String, String> entry : params.entrySet()) {
        String key = entry.getKey();
        String value = entry.getValue();
        intent.putExtra(key, value);
    }
    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
 }
}

Dann benötigen Sie auch einen Enum-Typ, um Fehler beim Codieren mit Zeichenfolgen zu vermeiden – (NotificationType):

public enum NotificationType {

   LoginResponse;
   // Others

}

Hier ist die Verwendung (Hinzufügen/Entfernen von Beobachtern) zum Beispiel in Aktivitäten:

public class LoginActivity extends AppCompatActivity{

    private BroadcastReceiver loginResponseReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
           // do what you need to do with parameters that you sent with notification

           //here is example how to get parameter "isSuccess" that is sent with notification
           Boolean result = Boolean.valueOf(intent.getStringExtra("isSuccess"));
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        //subscribe to notifications listener in onCreate of activity
        NotificationCenter.addObserver(this, NotificationType.LoginResponse, loginResponseReceiver);
    }

    @Override
    protected void onDestroy() {
        // Don't forget to unsubscribe from notifications listener
        NotificationCenter.removeObserver(this, loginResponseReceiver);
        super.onDestroy();
    }
}

und hier ist schließlich, wie wir eine Benachrichtigung von einem Rückruf- oder Ruhedienst oder was auch immer an das NotificationCenter senden:

public void loginService(final Context context, String username, String password) {
    //do some async work, or rest call etc.
    //...

    //on response, when we want to trigger and send notification that our job is finished
    HashMap<String,String> params = new HashMap<String, String>();          
    params.put("isSuccess", String.valueOf(false));
    NotificationCenter.postNotification(context, NotificationType.LoginResponse, params);
}

das ist es, Prost!

  • Danke für deine Lösung! Das habe ich mit gefunden Bundle params Anstatt von HashMap ist bequemer, um Parameter verschiedener Typen zu übergeben. Es gibt eine schöne Verbindung zwischen Intent und Bundle: intent.putExtras(params)

    – zubko

    2. Dezember 2018 um 9:59 Uhr

Sie könnten dies versuchen: http://developer.android.com/reference/java/util/Observer.html

  • Shikis Antwort unten ist viel besser.

    – dsaff

    2. November 2012 um 14:34 Uhr

  • @dsaff Obwohl es eine vollständigere Antwort ist, ist meine Antwort in keiner Weise falsch, ich verdiene eindeutig keine -1. Was Sinn macht, ist für Sie, Shikis Antwort +1 zu geben.

    – Rui Peres

    2. November 2012 um 14:46 Uhr

  • Shiki’s ist die bessere Antwort auf die Frage

    – Ramz

    25. Januar 2013 um 11:11 Uhr


  • Beachten Sie, dass nur technisch inkorrekte und Spam-Antworten herabgestuft werden sollten – diese passt in keine von beiden. +1 für die Entschädigung und +1 auch für Shiki, denn das ist eine großartige Antwort.

    Benutzer529758

    25. Januar 2013 um 14:32 Uhr

Ich habe festgestellt, dass die Verwendung von EventBus von Guava lib der einfachste Weg für die Kommunikation im Publish-Subscribe-Stil zwischen Komponenten ist, ohne dass die Komponenten explizit miteinander registriert werden müssen

siehe ihre Probe auf https://code.google.com/p/guava-libraries/wiki/EventBusExplained

// Class is typically registered by the container.
class EventBusChangeRecorder {
  @Subscribe public void recordCustomerChange(ChangeEvent e) {
    recordChange(e.getChange());
  }

// somewhere during initialization
eventBus.register(this);

}

// much later
public void changeCustomer() {
  eventBus.post(new ChangeEvent("bla bla") );
} 

Sie können diese Bibliothek einfach in Android Studio hinzufügen, indem Sie Ihrer build.gradle eine Abhängigkeit hinzufügen:

compile 'com.google.guava:guava:17.0'

Sie könnten dies verwenden: http://developer.android.com/reference/android/content/BroadcastReceiver.htmlwas zu einem ähnlichen Verhalten führt.

Sie können Empfänger programmgesteuert über Context.registerReceiver(BroadcastReceiver, IntentFilter) registrieren, und es werden Absichten erfasst, die über Context.sendBroadcast(Intent) gesendet werden.

Beachten Sie jedoch, dass ein Empfänger keine Benachrichtigungen erhält, wenn seine Aktivität (Kontext) angehalten wurde.

  • Ein kurzer Designhinweis: BroadcastReceivers und NSNotificationCenter können beide als Ereignisaggregator fungieren. Der Vorteil gegenüber Delegierten oder Beobachtern besteht darin, dass Sender und Empfänger entkoppelt sind (sie haben tatsächlich eine Nachrichten- oder Datenkopplung, aber das ist einer der schwächsten Kopplungstypen). Mit Korrektur bearbeitet.

    – AngraX

    26. September 2011 um 13:17 Uhr

Kotlin: Hier ist eine Version von @Shiki in Kotlin mit einem kleinen Refactor in einem Fragment.

  1. Registrieren Sie den Beobachter in Fragment.

Fragment.kt

class MyFragment : Fragment() {

    private var mContext: Context? = null

    private val mMessageReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            //Do something here after you get the notification
            myViewModel.reloadData()
        }
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)

        mContext = context
    }

    override fun onStart() {
        super.onStart()
        registerSomeUpdate()
    }

    override fun onDestroy() {
        LocalBroadcastManager.getInstance(mContext!!).unregisterReceiver(mMessageReceiver)
        super.onDestroy()
    }

    private fun registerSomeUpdate() {
        LocalBroadcastManager.getInstance(mContext!!).registerReceiver(mMessageReceiver, IntentFilter(Constant.NOTIFICATION_SOMETHING_HAPPEN))
    }

}
  1. Benachrichtigung überall posten. Nur Sie brauchen den Kontext.

    LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(Constant.NOTIFICATION_SOMETHING_HAPPEN))```
    

PS:

  1. Sie können eine Constant.kt wie mich hinzufügen, um die Benachrichtigungen gut zu organisieren.
    Konstante.kt
object Constant {
    const val NOTIFICATION_SOMETHING_HAPPEN = "notification_something_happened_locally"
}
  1. Für den Kontext in einem Fragment können Sie verwenden activity (manchmal null) oder conext wie das, was ich verwendet habe.

  • Ein kurzer Designhinweis: BroadcastReceivers und NSNotificationCenter können beide als Ereignisaggregator fungieren. Der Vorteil gegenüber Delegierten oder Beobachtern besteht darin, dass Sender und Empfänger entkoppelt sind (sie haben tatsächlich eine Nachrichten- oder Datenkopplung, aber das ist einer der schwächsten Kopplungstypen). Mit Korrektur bearbeitet.

    – AngraX

    26. September 2011 um 13:17 Uhr

Benutzer-Avatar
Michael Belhassen

Ich habe einen Wrapper geschrieben, der die gleiche Aufgabe erledigen kann, was iOS mit LiveData entspricht

Verpackung:

class ObserverNotify {
    private val liveData = MutableLiveData<Nothing>()


    fun postNotification() {
        GlobalScope.launch {
            withContext(Dispatchers.Main) {
                liveData.value = liveData.value
            }
        }
    }

    fun observeForever(observer: () -> Unit) {
        liveData.observeForever { observer() }
    }

    fun observe(owner: LifecycleOwner, observer: () -> Unit) {
        liveData.observe(owner) { observer()}
    }

}

class ObserverNotifyWithData<T> {
    private val liveData = MutableLiveData<T>()


    fun postNotification(data: T) {
        GlobalScope.launch {
            withContext(Dispatchers.Main) {
                liveData.value = data
            }
        }
    }

    fun observeForever(observer: (T) -> Unit) {
        liveData.observeForever { observer(it) }
    }

    fun observe(owner: LifecycleOwner, observer: (T) -> Unit) {
        liveData.observe(owner) { observer(it) }
    }

}

Beobachtertypen deklarieren:

object ObserverCenter {
    val moveMusicToBeTheNextOne: ObserverNotifyWithData<Music> by lazy { ObserverNotifyWithData() }
    val playNextMusic: ObserverNotify by lazy { ObserverNotify() }
    val newFCMTokenDidHandle: ObserverNotifyWithData<String?> by lazy { ObserverNotifyWithData() }
}

Bei der zu beachtenden Aktivität:

ObserverCenter.newFCMTokenDidHandle.observe(this) {
    // Do stuff
}

Bemerken:

ObserverCenter.playNextMusic.postNotification()
ObserverCenter.newFCMTokenDidHandle.postNotification("MyData")

  • Aber der Compiler sagt, dass es einen Fehler in “liveData.observe(owner) { Observer() }” und “liveData.observe(owner) { Observer(it) }” gibt.

    – Genar

    22. März 2021 um 17:32 Uhr

1316910cookie-checkAndroid-Äquivalent zu NSNotificationCenter

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy