Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable/Observer not working?

I tried implementing a static Observable in my Application subclass, but it's not working. No exceptions or error messages, but my update() callback doesn't get called.

MyApplication.java

public class MyApplication extends Application{
    public static Observable appObserver = new Observable();

    public void onCreate(){
        super.onCreate();        
    }

}

Foo.java

MyApplication.appObserver.notifyObservers( "Hello world" );

BarFragment.java

public class BarFragment extends Fragment implements Observer{

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);                
        MyApplication.appObserver.addObserver(this);
    }


    @Override
    public void onDestroy() {       
        MyApplication.appObserver.deleteObserver(this);
        super.onDestroy();
    }


    @Override
    public void update(Observable observable, Object data) {
        Log.i("BarFragment", data.toString()); // Should log, but doesn't
    }

}

What's more, I tried scribbling down a simple Observable of my own, and then everything worked like a charm with just substituting public static Observable appObserver = new Observable(); with public static MyObservable appObserver = new MyObservable();

MyObservable.java

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

    public void addObserver(Object observer){
        observers.add(observer);
    }

    public void notifyObservers(Object data){
        for( int i=0; i<observers.size(); i++ ){
            ((Observer) observers.get(i)).update(null, data);
        }
    }
}

What am I missing?

I'm testing this on a Nexus One with Android 2.3.6 if it matters.

like image 932
Magnus Avatar asked Feb 22 '14 23:02

Magnus


2 Answers

Seems I missed a crucial part of the Observer mechanism, apparently one has to call setChanged() before notifyObservers(). But the thing is, setChanged() is protected and thus only visible to any subclass of Observable.

So I guess it's not meant to be used in the fashion I tried to use it, but the hackish subclass below will work...

public class MyObservable extends Observable{

    @Override
    public boolean hasChanged() {
        return true; //super.hasChanged();
    }

}
like image 83
Magnus Avatar answered Sep 25 '22 18:09

Magnus


BadCash's answer actually didn't work for me, but my issue did stem from the same problem with Observable. Perhaps you're using an older implementation, but I'm on Java 8. Rather than overriding hasChanged(), I had to override notifyObservers() to always set itself to be changed before notifying:

class WorkingObservable extends Observable{
    @Override
    public void notifyObservers(){
        setChanged();
        super.notifyObservers();
    }
};

That did the trick for me. I looked at the source code and it seems that the Observable class doesn't call hasChanged() method internally to decide whether to notify. It just checks the changed private variable. This probably could have been implemented better.

like image 35
J-bob Avatar answered Sep 24 '22 18:09

J-bob