Frage

Can someone provide a simple example of using the Publish/SUbscribe singleton pattern to pass information between fragments. Last week I asked about passing data between fragments for the scenario below and this method was suggested; I can't seem to wrap my head around it.

I have an application using the navigation drawer layout, with various "sub applications" that perform standalone functions (for example, a calculators app, with unrelated "sub apps" for income tax calculations, metric/imperial conversions, etc). For a given calculator, I'd have a data entry/selection fragment and a data presentation fragment that displays the calculation in some meaningful type of way. Thus, my only activity in the application is the MainActivity, holding the navigation drawer and content pane. The question is: what is the best way to design the application such that the various calculators pass data to their data representation fragments, say on the click of a button?

War es hilfreich?

Lösung

All the examples in the internet s...ks, with their UML diagrams absolutely unclear to beginners and plenty of code where only experienced one can understand why using this not that, one not another... So, let's construct moving step by step and thinking logically.

First, you need to create some kind of storage in your singleton class - to make data not depend on fragments' lifecycle. Depending on purpose of your app it may be different kinds of collections or just primitives. Add such fields into you singleton, for example:

double conversionRate, taxRate;
int securityNumber;
.... // and so on

Now you need some method of your singleton which will update these data. Let's call it updateData(). Every time when some data in any of your fragments is changed by user, this fragment should invoke:

Singleton.getInstance().updateData(dataType, data);

As arguments let's put type of data and some object that contains these data.

Second, on every update you need to update data in other presentation fragments, right? So this updateData() method should run through list of fragments running at the moment and send new data to each. How to implement it? -- Very easy, via callback method. For that, you will need to:

1) create public interface a kind of Updateable with one method: public void onUpdate(int dataType, Data data)

2) implement this interface on every fragment by implements Updateable after class name

3) implement its only method onUpdate() in class body. In this implementation, each fragment will consider, first, whether it needs to use data of a given dataType, second, handle these received data (e. g. change its textview value):

@Override
onUpdate(int dataType, Data data){
   if (dataType == DATA_TAX_RATE){
      textViewTaxRate.setText(String.parseInt(data.getValue()));
   }

}

Third, how your singleton will know to whom it should send updated data? Very easy: just add a storage that will contain all fragments as Updateable objects in it:

List<Updateable> listeners = new ArrayList<Updateable>;

and add two additional methods to register and unregister objects (e. g. your fragments) as listeners. In first method you should just add a listener into mentioned list, in second remove it:

public void registerListener(Updateable listener){
  if (!listeners.contains(listener)) {
     listeners.add(listener);
  }
}

public void unregisterListener(Updateable listener){
  if (listener != null && listeners.contains(listener)){
     listeners.remove(listeners.indexOf(listener));
  }
}

Now, each fragment which wants to receive updates (i. e. implements Updateable interface) should register as a listener right after creation and resume:

Singleton.getInstance().registerListener(this);

and unregister on onDestroy or when it doesn't need to listen for updates anymore:

Singleton.getInstance().unregisterListener(this);

N.B.: to prevent memory leaks, you should unregister a listener when you are going not to use this object anymore. Otherwise reference to it will be kept in listeners list making it inaccessible to garbage collector!

After we created methods to add and remove listeners, let's return to singleton's method updateData() mentioned before. Its main purpose is to store new data and send updates to all listeners, so let's implement it:

public void updateData(int dataType, Data data){
   // store new data
   if (dataType == DATA_TAX_RATE){
       this.taxRate = data.getValue();
   }

   .....

   // then iterate through listeners and send updated data to them
   for (Updateable listener : listeners){
       try {
          listener.onUpdate(dataType, data);
       } catch (Throwable e) {}
   } 
}

Now, every time user updates some data in any of your fragments, or data are updated by calculation, just call Singleton.getInstance().updateData(...) from this fragment -- new data will be stored in singleton and broadcasted to other fragments automatically.

==================================================================

Disclaimer: this is not exact implementation of Observer design pattern, just its simplified version to be more clear and understandable for beginners. That's why I don't use common names such as Observer, notify etc. It's just working example for first step of understanding common design patterns more deeply.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top