Design Patterns in Android — Observer

Paulina Szklarska
4 min readSep 5, 2017

Design patterns are reusable solutions to the most commonly occurring software problems. They can speed up the development process by providing a proven way of resolving frequent issues.

In previous post I introduced Builder pattern. Now it’s time to meet the Observer!

Introduction

Observer pattern is one of the Behavioral Design Patterns, which means it gives us the way to communicate between different classes and objects. This pattern is the best approach if we have one-to-many relation and we’d like to inform other objects about some changes or actions.

You may know the Observer pattern from RxJava , where it’s implemented in the very extended way. We have there Observable, which is an object we’d like to observe (it may be also called Subject in the Observer pattern) and we can subscribe for observing changes in those object. Every object interested in those changes will be called Observer. We can have one Subject and many Observers, and single Observers may know nothing about each other. We can also stop observing changes at any time.

Observer pattern is also great solution for designing your application to follow OCP (the open/closed principle), one of the SOLID rules which says that your application should be open for extension, but closed for the modification.

Observer — example

In this article I’d like to show Observer on the real example. Let’s say we have some Button, which is checkable. Every time someone clicks on it, it changes state between ON and OFF. In Observer pattern we’ll call this Button Subject .

We also have some objects which are interested in Button’s state, e.g. every time Button is clicked, we’d like to show different message in every visible Fragment. Every Fragment, interested in Button’s state, here in this pattern will be called Observer.

Observer pattern gives us possibility to unsubscribe from observing the Subject in every moment, e.g. when we don’t want to show a message when Fragment is not visible.

To sum up, we have three fragments — Fragments A and B (our Observers) are interested in Button’s state. Button is located in the Fragment C (it’s our Subject). Everything is placed in the Activity. Let’s start!

Implementation

How to implement Observer pattern? We need to create interfaces for Subject and Observer . Our Subject needs to handle subscribing, unsubscribing and updating data:

public interface Subject {
public void register(Observer observer);
public void unregister(Observer observer);
public void notifyObservers();
}

And there’s complementary Observer, which main function will be receiving info about updates from Subject :

public interface Observer {
public void update(final boolean checked);
}

Now we need to implement those interfaces in proper places. Our Subject is Fragment C (ThirdFragment), because it has a Button:

public class ThirdFragment extends Fragment implements Subject {

private List<Observer> observers;
private ToggleButton button;

public ThirdFragment() {
observers = new ArrayList<>();
}
@Override
public void onViewCreated(final View view, @Nullable final
Bundle
savedInstanceState) {
button = (ToggleButton)
view.findViewById(R.id.toggle_button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
notifyObservers();
}
});
}
@Override
public void register(final Observer observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}

@Override
public void unregister(final Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers() {
for (final Observer observer : observers) {
observer.update(button.isChecked());
}
}
}

Fragment C implements three methods — for registering, unregistering and notifying observers. Thanks to those methods we’ll store our observers in the list and if there’s a need to notify them about some action, we can iterate through the list and run the proper callbacks.

We also see listener method set to the Button. Every time we click on the Button we call notifyObservers() so they all know about the event.

Now we can go to the Fragments A and B. They are both our Observers , so they need to implement one method:

public class SecondFragment extends Fragment implements Observer {

...

@Override
public void update(final boolean checked) {
if (checked) {
textView.setText("ON");
} else {
textView.setText("OFF");
}
}
}

Whenever some action occurs, we’ll be notified about this in this method, so we can e.g. show proper UI. Notice the boolean value checked — it’s the value passed from the Button.

To make it all work now we need to tell our Fragment C (Subscriber) to register Fragment A and B (Observers). We can use main activity to do this:

public class ObserverActivity extends AppCompatActivity {

@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

...

thirdFragment.register(firstFragment);
thirdFragment.register(secondFragment);
}
}

From now on, Fragments A and B are registered to Fragment C and they will be updated about state from Fragment C.

The last thing we need to remember about is unregistering from observing this fragment to avoid memory leak. And that’s all!

Conclusion

Observer pattern gives us loose coupling between single places in our application (e.g. between many fragments). Using this pattern a subject can register an unlimited number of observers interested on watching its state, and they don’t know about each other. It’s a great solution for implementing communication in modules with one-to-many relationships.

--

--

Paulina Szklarska

Flutter GDE / Flutter & Android Developer / blogger / speaker / cat owner / travel enthusiast