Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the preferred way to call an Android Activity back from a Service thread

I'm currently developing an Android application that has the following needs:

A worker thread started in a Service. This thread does some processing and needs to be invoked from the main Activity and provide some asynchronous answers to the same Activity.

Invoking the Service from the Activity is easy (IBinder stuff)

My question is now about the proper implementation of the service callback.

I was first going to add an android.os.Handler in the Activity and handle the thread's anwers in MyActivity.handleMessage(Message) but this requires that I give this handler's reference to the service. So what happens when the Android OS decides to destroy/recreate my Activity due to an orientation change for example ? Does my activity stay alive as it is referenced (indirectly) in the service ? If the Activity destroyed/rebuilt anyway, what happens to my Handler reference in the Service ?

I guess I'm not using the right method to callback an Activity from a Service thread, so I wanted to know if someone can point me the correct way of doing.

TIA

like image 655
alberthier Avatar asked Mar 14 '13 15:03

alberthier


2 Answers

I prefer using LocalBroadcastManager

Here's an example for the code in your Activity:

BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Log.d("BroadcastReceiver", "Message received " + intent.getAction());
        Log.d("BroadcaseReceiver", "Received data " + intent.getStringExtra("com.my.package.intent.EXTRA_DATA"));
    }
};

@Override
protected void onStart()
{
    super.onStart();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    final IntentFilter localFilter = new IntentFilter();
    localFilter.addAction("com.my.package.intent.ACTION_NAME_HERE");
    localBroadcastManager.registerReceiver(localBroadcastReceiver, localFilter);
}

@Override
protected void onStop()
{
    super.onStop();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    // Make sure to unregister!!
    localBroadcastManager.unregisterReceiver(localBroadcastReceiver);
}

Anywhere else in your codebase (such as in the completion of your background thread):

final LocalBroadcastManager localBroadcastManager =
    LocalBroadcastManager.getInstance(context);
final Intent intent = new Intent("com.my.package.intent.ACTION_NAME_HERE")
intent.putExtra("com.my.package.intent.EXTRA_DATA", yourBackgroundData);
localBroadcastManager.sendBroadcast(intent);

You can, of course, use intent.putExtra to add any additional data or use multiple actions to differentiate broadcast messages.

like image 136
ianhanniballake Avatar answered Sep 17 '22 16:09

ianhanniballake


We've done this by centralizing all communication between activities and service in the Application class. We extend the Application class and then have methods there that bind to the service and accept the callbacks. There is no direct connection between an Activity and the Service in this architecture.

The advantage of this mechanism is that you don't have to worry about unbinding/rebinding to the service during activity transitions and activity death and recreations. The Application class manages all this and it isn't affected by what activities do. The Application class receives all the callbacks, and you will need to have code there to determine what to do with the callbacks. Probably you will want to store some data in the Application class and then notify the activities that there is new data available, or something similar.

Another approach is to have the Service broadcast the callbacks. In this case the coupling between the service and the activities is loose, so you wouldn't need to create a Handler in the activity and then pass it to the Service. Activities can just register BroadcastReceivers for the callbacks they are interested in, or you can manage this in the manifest.

like image 27
David Wasser Avatar answered Sep 16 '22 16:09

David Wasser