Monday, 3 October 2016

Android - Communicating between BroadcastReceiver and Activity


Suppose you have a broadcast receiver in your app which is fired every time the user gets an incoming call. When it happens, you need the broadcast receiver to invoke a specific method in a specific activity. You can try to make this method static and therefore available, but is there a better way to do this?
First of all, let's understand the different ways of declaring a BroadcastReceiver in Android.

1) You can declare the receiver in your Manifest.xml file. The Receiver will be a static one and will exist till the lifetime of your application. You should do this if you want to listen for and respond to broadcasts even when your activity is not at the foreground.
2) You can register and unregister it within your Activity. The receiver is listening for broadcasts as long as the Activity is active. Typically, you should use this when you want the receiver to make some changes in the activity as long as the activity is active.
Communication is pretty straightforward in the second case where you can directly use the instance of the activity to make changes to the member variables. 
You can use the pattern:
public class MyActivity extends Activity {
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(...) {
            ...
        }
   });

    public void onResume() {
        super.onResume();

        IntentFilter filter = new IntentFilter();
        filter.addAction(BROADCAST_ACTION);

        this.registerReceiver(this.receiver, filter);
    }

    public void onPause() {
        super.onPause();

        this.unregisterReceiver(this.receiver);
    }
}
So, this way the receiver is instantiated when the class is created (could also do in onCreate). Then in the onResume/onPause, handle registering and unregistering the receiver. Then in the reciever's onReceive method, do whatever is necessary to make the activity react the way you want to when it receives the broadcast.

However if you tried to instantiate the broadcast receiver inside your activity without declaring it in the manifest - when the app is off, the activity does not exist and you can't invoke your method. You have to go for method 1 then. Now, your communication will be some kind of data from the receiver which you want in your Activity. 
You can use the Observer Design Pattern to update an Observable and add the Activity as a listener to that Observable.
Example:
public class MyReceiver extends BroadcastReceiver {
    public MyReceiver() {
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        ObservableObject.getInstance().updateValue(intent);
    }
}

public class MainActivity extends Activity implements Observer {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ObservableObject.getInstance().addObserver(this);
    }

    @Override
    public void update(Observable observable, Object data) {            
        Toast.makeText(this, String.valueOf("activity observer " + data), Toast.LENGTH_SHORT).show();
    }
}

public class ObservableObject extends Observable {
    private static ObservableObject instance = new ObservableObject();

    public static ObservableObject getInstance() {
        return instance;
    }

    private ObservableObject() {
    }

    public void updateValue(Object data) {
        synchronized (this) {
            setChanged();
            notifyObservers(data);
        }
    }
}
Receiver is used via manifest. ObservableObject - must be a singleton.


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. After notification, each observer carries out its task via a separate thread as to prevent blocking. It is mainly used to implement distributed event handling systems. The Observer pattern is also a key part in the familiar model–view–controller (MVC) architectural pattern. The observer pattern is implemented in numerous programming libraries and systems, including almost all GUI toolkits. It can cause memory leaks, known as the lapsed listener problem, because in basic implementation it requires both explicit registration and explicit deregistration because the subject holds strong references to the observers, keeping them alive. This can be prevented by the subject holding weak references to the observers. A weak reference is a reference that does not protect the referenced object from collection by a garbage collector


How do we create a weak reference?
WeakReference<String> wr = new WeakReference<String>(new String("abc"));
The object (in this case a String) which needs to be weakly referenced is wrapped inside a WeakReference object. We can get the String back by using the get method as shown below:
String s = wr.get();
if(s != null ) {
    // great the weak ref has not been garbage collected
} else {
    // oops the weak ref was garbage collected... now I will have to create another one
}
The most common use for weak references are read-only caches, where losing an object is not disastrous. It just means we have to recreate the object, usually back from the database.

10 comments:

  1. This is really informative. Especially the design pattern part. Thanks!

    ReplyDelete
  2. Thanks a lot! You made a new blog entry to answer my question; I really appreciate your time and effort.
    Best Android Training in Velachery | android development course fees in chennai

    ReplyDelete
  3. Great and that i have a dandy proposal: Where To Buy Houses For Renovation home repairs contractors near me

    ReplyDelete