Эквивалент iOS NSNotificationCenter в Android?

Есть ли эквивалент класса iOS NSNotificationCenter в Android? Существуют ли библиотеки или полезный код для меня?

Ответ 1

В Android нет центрального центра уведомлений, как в ios. Но вы можете в основном использовать Observable и Observer объекты для достижения своей задачи.

Вы можете определить класс как что-то ниже, просто измените его для использования в одиночном режиме и добавьте синхронизированный для одновременного использования, но идея одинаков:

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

Ответ 2

Взгляните на шину событий Отто с площади:

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

Он имеет по существу те же функции, что и NSNotificationCenter, но благодаря аннотациям и статической типизации легче следить за зависимостями компонентов и путей, за которыми следуют события. Это гораздо проще в использовании, чем у Android API для Android, IMO.

Ответ 3

У меня были те же чудеса.. так я написал это:

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

}

и использование для этого будет:

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

попытался сделать интерфейс как можно более похожим на IOS, но проще (без необходимости регистрации объекта).

надеюсь, что поможет:)

Ответ 4

Если вы не хотите использовать Observer - это может быть проблематично в случаях, когда вы хотите, чтобы фрагмент был вашим наблюдателем, вы не можете продлить более одного класса, Вы можете использовать Google Guava Library (https://code.google.com/p/guava-libraries/) для "Function" и "Multimap" - хотя вы также можете использовать HashMap > для subscibersCollection

и реализуем что-то вроде этого:

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

Ответ 5

На основе ответа Behlül я изменяю код, чтобы приблизить его к iOS NSNotificationCenter.

Другое дело: уведомления будут стрелять по основному потоку

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

Пример прослушивателя:

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