Improved TextView Observer Design Pattern

In the previous post we explicitly register each observer to the subject. it is more useful to have the observers register and unregister themselves once the views are attached and detached from the screen respectively. This means we never need to worry about adding extra code to deal with unregistering a particular observer during lifecycle events. Here is an improved UIConfigAwareTextView that does that

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);
	}
	
	@Override
	protected void onAttachedToWindow()
	{
		super.onAttachedToWindow();
		if(getContext() instanceof UIConfigGetter){
			((UIConfigGetter)getContext()).getUIConfig().registerObserver(this);
		}
	}
	
	@Override
	protected void onDetachedFromWindow()
	{
		if(getContext() instanceof UIConfigGetter){
			((UIConfigGetter)getContext()).getUIConfig().unregisterObserver(this);
		}
		super.onDetachedFromWindow();
	}
	
	@Override
	public void update(UIConfig uiConfig)
	{
		this.setTextColor(uiConfig.getFontColor());
	}
}

Also here is a more complete UIConfig model that uses a Handler and synhronizes the observers list. This version will also notify observers once they are added to the observer list so as to ensure they always recieve the latest font color as soon as the view is attached. In order to achieve notifying single observers we can add another method to the UIConfigSubject interface (scroll down for this)

public class UIConfig implements UIConfigSubject
{
	private static final String TAG = UIConfig.class.getSimpleName();
	
	private ArrayList<UIConfigObserver> mObservers = new ArrayList<UIConfigObserver>();
	private Object mObserversLock = new Object();
	private Handler mHandler = null;
	private boolean mPostPending = false;
	
	/** UIConfig properties */
	private int mFontColor;
	
	public UIConfig()
	{
		//
	}
	
	public void setHandler(Handler handler)
	{
		mHandler = handler;
		if(mPostPending){
			mPostPending = false;
			notifyObservers();
		}
	}
	
	@Override
	public void registerObserver(UIConfigObserver observer)
	{
		synchronized (mObserversLock){
			mObservers.add(observer);
			notifyObservers();
		}
	}
	
	@Override
	public void unregisterObserver(UIConfigObserver observer)
	{
		synchronized (mObserversLock){
			mObservers.remove(observer);
		}
	}
	
	@Override
	public void notifyObservers()
	{
		synchronized (mObserversLock){
			if(mHandler != null){
				mHandler.post(new NotifyAllRunnable());
			}
			else{
				mPostPending = true;
			}
		}
	}
	
	@Override
	public void notifyObserver(UIConfigObserver observer)
	{
		mHandler.post(new NotifySingleRunnable(observer));
	}
	
      	private class NotifySingleRunnable implements Runnable
	{
		
		private UIConfigObserver mNewestObserver;
		
		
		public NotifySingleRunnable(UIConfigObserver observer)
		{
			mNewestObserver = observer;
		}
		
		@Override
		public void run()
		{
			Log.w(TAG, "Notifying Single observer.");
			mNewestObserver.update(UIConfig.this);
		}
	}
	
	private class NotifyAllRunnable implements Runnable
	{
		public NotifyAllRunnable()
		{
			//
		}
		
		@Override
		public void run()
		{
			Log.w(TAG, "Notifying " + mObservers.size() + " observers.");
			for(UIConfigObserver ob : mObservers){
				ob.update(UIConfig.this);
			}
		}
	}
	
	public void copyProperties(UIConfig uiConfig)
	{
		setFontColor(uiConfig.getFontColor());
	}
	
	public void setFontColor(int fontColor)
	{
		this.mFontColor = fontColor;
		notifyObservers();
	}

	public int getFontColor()
	{
		return mFontColor;
	}
}

Here is the revised interface

public interface UIConfigSubject
{
	public void registerObserver(UIConfigObserver observer);
	
	public void unregisterObserver(UIConfigObserver observer);
	
	public void notifyObservers();
	
        //This allows us to notify observers independently
	public void notifyObserver(UIConfigObserver observer);
}
Tagged , , , ,

Leave a comment