The following is an example of how to use observer pattern in java on the Android platform.

Observer pattern (from wikipedia):

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems

The scenario

Imagine we are writing an app that needs the ability to change the color of every TextView on the screen at runtime. At first we might start to write code that allows us to keep a reference to every view and then call the setTextColor() on every single view systematically each time we want to change the color. The problem with this is that there could be many TextView’s on the screen, including ListView’s that contain TextView’s and fragments that contain TextView’s…this could start to get very messy! Observer Pattern can solve this problem.

In our example we will make a custom TextView that is setup to be an observer. We will also create a UIConfig class, this will be the subject of observation. We will make our custom TextView’s register as observers to the subject by adding themselves to a List that is contained in the subject (the UIConfig class). By doing this we can automagically call a method inside our observers whenever a particular change occurs in the subject.

STEP 1 – Create an Interface that our UIConfig object (the subject) will implement

public interface UIConfigSubject { public void registerObserver(UIConfigObserver observer); public void removeObserver(UIConfigObserver observer); public void notifyObservers(); }

STEP 2 – Create an interface that each of our TextView’s (the observers) will implement

public interface UIConfigObserver{ public void update(UIConfig uiConfig); }

Now lets build a couple of concrete classes that will implement these interfaces.

Firstly, here is how we make the UIConfig class, a class that is a subject of observation to any class that has implemented the above UIConfigObserver interface and registered itself as an observer (notice the List member which holds a reference to each observer)

public class UIConfig implements UIConfigSubject{ //we keep a list of current observers. //Any class that implements the UIConfigObserver interface can be //added to the list, its not just limited to our custom TextView! private List<UIConfigObserver> mObservers = new ArrayList<UIConfigObserver>(); private String mFontColor; public UIConfig(String color){ mFontColor = color; } public String getFontColor(){ return mFontColor; } public void setFontColor(String fontColor){ this.mFontColor = fontColor; //Whenever our color changes we simply call the notify method to call the update methods... notifyObservers(); } @Override public void registerObserver(UIConfigObserver observer){ mObservers.add(observer); } @Override public void removeObserver(UIConfigObserver observer){ mObservers.remove(observer); } @Override public void notifyObservers(){ //We just loop through the list of observers and call their update() for(UIConfigObserver ob : mObservers){ ob.update(this); } } }

Next lets extend TextView and make a custom view that is ready to observe the UIConfig by means of implementing the UIConfigObserver interface

public class UIConfigAwareTextView extends TextView implements UIConfigObserver{ public UIConfigAwareTextView(Context context){ this(context, null); } public UIConfigAwareTextView(Context context, AttributeSet attrs){ this(context, attrs, android.R.attr.textViewStyle); } public UIConfigAwareTextView(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle); } //Whenever the UIConfig objects notify() method is called, this will be called @Override public void update(UIConfig uiConfig){ this.setTextColor(Color.parseColor(uiConfig.getFontColor())); } }

Here is how we create some UIConfigAwareTextView’s and register them as observers of a UIConfig object

... UIConfigAwareTextView tv1 = (UIConfigAwareTextView)findViewById(R.id.tv1); UIConfigAwareTextView tv2 = (UIConfigAwareTextView)findViewById(R.id.tv2); UIConfig uiConfig = new UIConfig("#FFFFFF"); uiConfig.registerObserver(tv1); uiConfig.registerObserver(tv2); ... //Lets change the color uiConfig.setFontColor("#FF0000"); //All registered UIConfigAwareTextView's are now red! ...

Now whenever the setFontColor() is called on our UIConfig object our UIConfigAwareTextView’s will have their update() method called and their text color will change! Groovy eh?

How to make this work if our UIConfigAwareTextView is inside a fragment…

Create another interface which will be implemented on the Activity that is holding the fragment. This will be used in order to expose the UIConfig inside the activity to its child fragments.

public interface UIConfigGetter{ public UIConfig getUIConfig(); }

Now consider the following Fragment, it will hold a UIConfigGetter that is initialized to the parent activity inside the fragments onAttach() method (remember that we must implement the above interface onto the Activity in order for this to work)

public class MyFragment extends Fragment{ private UIConfigGetter mUIconfigGetter; private UIConfigAwareTextView mTv1; public static MyFragment newInstance(){ MyFragment myFragment = new MyFragment(); return myFragment; } @Override public void onAttach(Activity activity){ super.onAttach(activity); if(activity instanceof UIConfigGetter){ //Get a reference to the UIConfig interface implemented on the Activity mUIconfigGetter = (UIConfigGetter)activity; } } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){ return inflater.inflate(R.layout.my_layout, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState); mTv1 = new (UIConfigAwareTextView)view.findViewById(R.id.mTv1); //Register the view as an observer mUIconfigGetter.getUIConfig().registerObserver(mTv1); } }

What if we want to use our UIConfigAwareTextView inside a listview?

We register the TextView’s that are being used in the getView() method of the adapter as observers. As long as we have a reference to the UIConfigGetter interface we are good to go!

For example:

private class MyBaseAdapter extends BaseAdapter{ ... public View getView(int position, View convertView, ViewGroup parent){ ViewHolder viewHolder; if(convertView == null){ convertView = mInflater.inflate(R.layout.gridview_awards_cell, parent, false); viewHolder = new ViewHolder(); viewHolder.tv = (UIConfigAwareTextView)convertView.findViewById(R.id.tv); viewHolder.tv.setTextColor(Color.parseColor(mUIconfigGetter.getUIConfig().getFontColor())); //The UIConfigGetter would be initialized inside the fragment onAttach() as before mUIconfigGetter.getUIConfig().registerObserver(viewHolder.tv); convertView.setTag(viewHolder); } else{ viewHolder = (ViewHolder)convertView.getTag(); } viewHolder.award.setText(mData.get(position).getAwardName()); return convertView; } ... }