2012-04-26 17 views
11

¿Hay un equivalente de la clase de iOS NSNotificationCenter en Android? ¿Hay alguna biblioteca o código útil disponible para mí?¿Equivalente de iOS NSNotificationCenter en Android?

+0

¿Se refiere a NSNotificationCenter, o al tono de notificación? – CodaFi

+0

NSNotificationCenter aunque no sé qué tono de notificación es :) Mi necesidad es transmitir eventos a múltiples observadores a través del patrón de observador. – user310291

+1

Parece que la [API de LocalBroadcastRecievers] (http://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html) es lo que está buscando. – CodaFi

Respuesta

17

En Android no hay un centro de notificaciones central como en ios. Pero básicamente puede usar los objetos Observable y Observer para lograr su tarea.

Se puede definir una clase como algo más adelante, basta con modificar para su uso Singleton y añadir sincronizado para el uso simultáneo, pero la idea es la misma:

public class ObservingService { 
    HashMap<String, Observable> observables; 

    public ObservingService() { 
     observables = new HashMap<String, Observable>(); 
    } 

    public void addObserver(String notification, Observer observer) { 
     Observable observable = observables.get(notification); 
     if (observable==null) { 
      observable = new Observable(); 
      observables.put(notification, observable); 
     } 
     observable.addObserver(observer); 
    } 

    public void removeObserver(String notification, Observer observer) { 
     Observable observable = observables.get(notification); 
     if (observable!=null) {   
      observable.deleteObserver(observer); 
     } 
    }  

    public void postNotification(String notification, Object object) { 
     Observable observable = observables.get(notification); 
     if (observable!=null) { 
      observable.setChanged(); 
      observable.notifyObservers(object); 
     } 
    } 
} 
+0

OK gracias por la muestra de código :) – user310291

+0

Antes de llamar a "notifyObservers()" necesita (o al menos en mi caso) llamar al método "setChanged()". Así que creé mi Custom Observable: http://pastebin.com/hqCuKRzW – jihonrado

+0

Edité mi respuesta original @jihonrado, gracias –

8

Tome una mirada en el bus de eventos Otto de la plaza:

http://square.github.com/otto/

se tiene esencialmente las mismas características que NSNotificationCenter pero gracias a las anotaciones y los tipos estáticos, es más fácil de seguir las dependencias de componentes y caminos que siguen los acontecimientos. Es mucho más fácil de usar que la API de difusión de Android, IMO.

2

Si no desea utilizar Observador - que puede ser problemático en los casos que desea un fragmento a su Observador porque no se puede extender más de una clase- Puede utilizar la biblioteca de guayaba de Google (https://code.google.com/p/guava-libraries/) para "Función" y "Multimapa" - aunque se puede usar también HashMap> para el subscibersCollection

e implementar algo como esto:

import java.util.Collection; 
import com.google.common.collect.ArrayListMultimap; 
import com.google.common.base.Function; 

public class EventService { 

    ArrayListMultimap<String, Function<Object, Void>> subscibersCollection; 

    private static EventService instance = null; 

    private static final Object locker = new Object(); 

    private EventService() { 
     subscibersCollection = ArrayListMultimap.create(); 
    } 

    public static EventService getInstance() { 
     if (instance == null) { 
      synchronized (locker) { 
       if (instance == null) { 
        instance = new EventService(); 
       } 
      } 
     } 
     return instance; 
    } 

    /** 
    * Subscribe to the notification, and provide the callback functions in case 
    * notification is raised. 
    * 
    * @param notification 
    *   - notification name 
    * @param func 
    *   - function to apply when notification is raised 
    */ 
    public void addSubscription(String notification, Function<Object, Void> func) { 
     synchronized (subscibersCollection) { 
      if (!subscibersCollection.containsEntry(notification, func)) { 
       subscibersCollection.put(notification, func); 
      } 
     } 
    } 

    /** 
    * Remove subscription from notification 
    */ 
    public void removeSubscription(String notification, 
      Function<Object, Void> func) { 
     synchronized (subscibersCollection) { 
      subscibersCollection.remove(notification, func); 
     } 
    } 

    /** 
    * raise notification for all its subscribers 
    * 
    * @param notification 
    *   - notification name 
    * @param data 
    *   - update data 
    */ 
    public void publish(String notification, Object data) { 
     Collection<Function<Object, Void>> observableList = subscibersCollection 
       .get(notification); 
     for (Function<Object, Void> func : observableList) { 
      func.apply(data); 
     } 
    } 
} 
2

sobre la base de la respuesta Behlul, cambio el código para hacer más cerca de iOS NSNotificationCenter.

Otra cosa: las notificaciones se disparará en el hilo principal

package com.oxygen.utils; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 

import android.os.Handler; 

public class NotificationCenter { 

//---------------- event type list --------------------- 

    public static enum NotificationID{ 
     IMAGES_CACHE_READY 
    } 


//---------------- singelton ---------------------------  

     private static NotificationCenter instance = null; 

     private NotificationCenter() { observables = new HashMap<NotificationID, MyObservable>(); } 

     public static synchronized NotificationCenter singelton() { 
      if (instance == null) { 
         instance = new NotificationCenter(); 
      } 
      return instance; 
     } 

//------------------------------------------- 

       public class Notification { 

        private Object poster; // the object that post the event 
        private Object info; // event specific data 
        private NotificationID id;  // event name 

        public Notification(Object poster, NotificationID id, Object info) { 
         super(); 
         this.poster = poster; 
         this.info = info; 
         this.id = id; 
        } 

        public Object getPoster() { 
         return poster; 
        } 

        public Object getInfo() { 
         return info; 
        } 

        public NotificationID getId() { 
         return id; 
        } 
       } 
     //------------------------------------------- 

       public interface Notifiable { 
        public void onNotification(Notification notify); 
       } 

//------------------------------------------- 

     protected class MyObservable { 
      List<Notifiable> observers = new ArrayList<Notifiable>(); 

      public MyObservable() { 
      } 

      public void addObserver(Notifiable observer) { 
       if (observer == null) { 
        throw new NullPointerException("observer == null"); 
       } 
       synchronized (this) { 
        if (!observers.contains(observer)) 
         observers.add(observer); 
       } 
      } 

      public int countObservers() { 
       return observers.size(); 
      } 

      public synchronized void deleteObserver(Notifiable observer) { 
       observers.remove(observer); 
      } 

      public synchronized void deleteObservers() { 
       observers.clear(); 
      } 

      public void notifyObservers(Notification notify) { 
       int size = 0; 
       Notifiable[] arrays = null; 
       synchronized (this) { 
         size = observers.size(); 
         arrays = new Notifiable[size]; 
         observers.toArray(arrays); 
       } 
       if (arrays != null) { 
        for (Notifiable observer : arrays) { 
         observer.onNotification(notify); 
        } 
       } 
      } 
     } 

//------------------------------------------- 

     HashMap<NotificationID, MyObservable > observables; 

     public void addObserver(NotificationID id, Notifiable observer) { 
      MyObservable observable = observables.get(id); 
      if (observable==null) { 
       observable = new MyObservable(); 
       observables.put(id, observable); 
      } 
      observable.addObserver(observer); 
     } 

     public void removeObserver(NotificationID id, Notifiable observer) { 
      MyObservable observable = observables.get(id); 
      if (observable!=null) {   
       observable.deleteObserver(observer); 
      } 
     } 

     public void removeObserver(Notifiable observer) { 
      for (MyObservable observable : observables.values()) { 
       if (observable!=null) {   
        observable.deleteObserver(observer); 
       }  
      } 
     } 

     public void postNotification(final Object notificationPoster, final NotificationID id, final Object notificationInfo) { 

      final MyObservable observable = observables.get(id); 
      if (observable!=null) { 

       // notification post to the maim (UI) thread  
       // Get a handler that can be used to post to the main thread 
       Handler mainHandler = new Handler(AppContext.get().getMainLooper()); 

       Runnable myRunnable = new Runnable() { 

        @Override 
        public void run() { 
         observable.notifyObservers(new Notification(notificationPoster, id, notificationInfo)); 
        } 
       }; 

       mainHandler.post(myRunnable); 
      } 
     } 
} 

Oyente de la muestra:

public class CustomGridViewAdapter extends ArrayAdapter<Category> implements Notifiable { 
    int layoutResourceId; 

    public CustomGridViewAdapter(Context context, int layoutResourceId) { 
     super(context, layoutResourceId); 
     this.layoutResourceId = layoutResourceId; 

     loadCategories(false); 
     NotificationCenter.singelton().addObserver(NotificationID.IMAGES_CACHE_READY, this); 
    } 

    public void onDestroy() { 
     NotificationCenter.singelton().removeObserver(this);    
    } 

    @Override 
    public void onNotification(Notification notify) { 
     switch (notify.getId()) { 
     case IMAGES_CACHE_READY: 
      loadCategories(true); 
      break; 
     } 
    } 
... 
} 
6

que tenía las mismas wondrings .. Así que escribí esto:

public class NotificationCenter { 

    //static reference for singleton 
    private static NotificationCenter _instance; 

    private HashMap<String, ArrayList<Runnable>> registredObjects; 

    //default c'tor for singleton 
    private NotificationCenter(){ 
     registredObjects = new HashMap<String, ArrayList<Runnable>>(); 
    } 

    //returning the reference 
    public static synchronized NotificationCenter defaultCenter(){ 
     if(_instance == null) 
      _instance = new NotificationCenter(); 
     return _instance; 
    } 

    public synchronized void addFucntionForNotification(String notificationName, Runnable r){ 
     ArrayList<Runnable> list = registredObjects.get(notificationName); 
     if(list == null) { 
      list = new ArrayList<Runnable>(); 
      registredObjects.put(notificationName, list); 
     } 
     list.add(r); 
    } 

    public synchronized void removeFucntionForNotification(String notificationName, Runnable r){ 
     ArrayList<Runnable> list = registredObjects.get(notificationName); 
     if(list != null) { 
      list.remove(r); 
     } 
    } 

    public synchronized void postNotification(String notificationName){ 
     ArrayList<Runnable> list = registredObjects.get(notificationName); 
     if(list != null) { 
      for(Runnable r: list) 
       r.run(); 
     } 
    } 

} 

y un uso para esto será:

NotificationCenter.defaultCenter().addFucntionForNotification("buttonClick", new Runnable() { 
     @Override 
     public void run() { 
      Toast.makeText(MainActivity.this, "Hello There", Toast.LENGTH_LONG).show(); 
     } 
    }); 

intentado hacer que la interfaz sea lo más similar posible a IOS, pero más simple (no se necesita registro de objeto).

espero que ayude :)

+1

Solución muy limpia. – pstoppani

Cuestiones relacionadas