1

There are a few threads running in a service. The threads need to post messages to UI / Activity

How would I pass over the Handler reference to the threads ? so that they can post their state changes to Activity ?

Or Better yet is there a way to globally expose handler ref like this ?

   Handler getUIHandler();

Thank you in advance ;)

Ahmed
  • 14,503
  • 22
  • 92
  • 150
  • Check out this previous discussion. http://stackoverflow.com/questions/2463175/how-to-have-android-service-communicate-with-activity – Simon Nov 13 '12 at 21:58

3 Answers3

0

Create a Handler object in your UI thread. You can just create it at instantiation time if you like. Any thread launched from your activity can post messages or runnables to that handler. Threads launched from other activities, services, or whatnot will not work because there's no guarantee that your Activity is even running. (Actually, it might be a fun experiment to see if it works when the Activity is running, but you could never base a real app on this technique.)

In fact, you don't even need to create a Handler. Every View object contains its own Handler, so you can simply post your runnables to a view.

Or you could just call runOnUiThread()

From my notes on Handlers:

Usage patterns:

Pattern 1, handler plus runnables:

// Main thread
private Handler handler = new Handler()

  ...

// Some other thread
handler.post(new Runnable() {
  public void run() {
    Log.d(TAG, "this is being run in the main thread");
  }
});

Pattern 2, handler plus messages:

// Main thread
private Handler handler = new Handler() {
  public void handleMessage(Message msg) {
    Log.d(TAG, "dealing with message: " + msg.what);
  }
};

  ...

// Some other thread
Message msg = handler.obtainMessage(what);
handler.sendMessage(msg);

Pattern 3, call runOnUiThread():

// Some other thread
runOnUiThread(new Runnable() {      // Only available in Activity
  public void run() {
    // perform action in ui thread
  }
});

Pattern 4, use the built-in handler of a View:

// Some other thread
myView.post(new Runnable() {
  public void run() {
    // perform action in ui thread, presumably involving this view
  }
});
Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • Thanks, I like the patterns you've posted, but I was asking about how to access Handler reference in the threads. If the threads reside in a service which is part of the same process as the activity, are we still not sure activity would exist ??? even though the service is ?? As per my knowledge the service and activity of the same process share the same thread. Is it not ? – Ahmed Nov 13 '12 at 22:42
  • If the service was launched from the activity, then the activity *probably* still exists while the service is running, but there are no guarantees. As I said, it would be an interesting experiment to see if threads in the service could access handlers in the activity, but without those guarantees, there's not much point. – Edward Falk Nov 13 '12 at 23:07
0

I've answered a similar question on how to report back to activity an error in the service.

Check Best practice for error handling in an Android Service, that will give you the aproach as well as a code example that you can use.

Regards.

Community
  • 1
  • 1
Luis
  • 11,978
  • 3
  • 27
  • 35
0

OK, maybe we should get back to the base issue. Are you trying to make UI updates in your activity from the service? I see two approaches to this.

First, your service could send special Intents back up to the activity. Declare the activity with a launch mode of "singleTask" and implement onNewIntent() to receive intents from the service. Then, pack any relevant information into the intent and send it to the activity to be handled.

The better way, but somewhat more complicated, would be to bind the service from the activity, and then they can easily communicate with each other over the binder. If the service and activity are both part of the same application, and both running in the same process, this becomes much simpler.

Again, from my notes:

Declare an inner class named e.g. "LocalBinder" which extends Binder and contains a method named e.g. getService() which returns the instance of the service:

public class MyService extends Service
{
  public class LocalBinder extends Binder {
    MyService getService() {
      return MyService.this;
    }
  }

  private final IBinder binder = new LocalBinder();

  public IBinder onBind(Intent intent) {
    return binder;
  }
}

Your activity contains code that looks like:

// Subclass of ServiceConnection used to manage connect/disconnect
class MyConnection extends ServiceConnection {
  public void onServiceConnected(ComponentName name, IBinder svc) {
    myService = ((MyService.LocalBinder)svc).getService();
    // we are now connected
  }
  public void onServiceDisconnected(ComponentName name) {
    // we are now disconnected
    myService = null;
  }
}

private MyService myService;
private MyConnection connection = new MyConnection();

/**
 * Bind to the service
 */
void doBind() {
  bindService(new Intent(MyClient.this, MyService.class),
    connection, Context.BIND_AUTO_CREATE);
}

/**
 * Unbind from the service
 */
void doUnbind() {
  if (connection != null) {
    unbindService(connection);
  }
}
Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • Just a further thought: the first method has the advantage that it brings your Activity back on the screen when it's time for a UI update, and the second method has the advantage that you can arrange for the service to exit if the activity does. – Edward Falk Nov 14 '12 at 16:38