Observers and Observables in Android
Within the android framework there’s a somewhat vague usage of the MVC pattern. We can see it happening with Activities, Adapters of all kinds and in fragments as well. But there’s a hidden gem within the java.util package which can be used very easily as the grounds for a publisher subscriber needed scenarios : java.util.Observer, java.util.Observable.
The approach is quite easy to grasp and is identical to the usage in other platforms and programming languages. The Observer announces that he wishes to subscribe to events and the publisher holds a list of subscribers which he can notify on data being changed with a simple callback.
In this very simple example, there’s an activity which contains a TextView which is updated by values. The Activity implements the Observer interface, which forces it to implement the update(Observable observable, Object data){} which will be invoked by the publisher, the parameters are the reference to the publisher and the data that is being published.
On the other hand there’s an entity which is the publisher, which has the responsibility to do some work and notify on data changes to it’s subscribers.
The entity needs to extends the Observable class, and that’s it pretty much. once it need to publish an update to it’s subscribers it simply sets its “changed” flag with setChanged(), followed by the notifyObservers(data) call.
Quick dirty example: (the example is really a forced one, but you will get the hang of it)
package com.shmoontz.observertutorial;
import java.util.Observable;
import java.util.Observer;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class MainActivity extends Activity implements Observer {
private Model mModel;
private TextView mTextView;
@SuppressWarnings("unchecked")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.clicks_counter);
mModel = new Model();
mModel.addObserver(this);
mModel.start();
}
@Override
public void update(Observable observable, Object data) {
mTextView.setText(String.valueOf(data));
}
@SuppressWarnings("rawtypes")
public class Model extends Observable {
private static final int N = 10;
private final String TAG = Model.class.getSimpleName();
int mCounter;
public void start() {
for (int i = 1; i < N; i++) {
mCounter += i;
Log.d(TAG, "observers count=" + countObservers()
+ ", now notifying the observers that current sum is "
+ mCounter);
setChanged();
notifyObservers(mCounter);
}
}
public int getCurrentData() {
return mCounter;
}
}
}
Comments