Java – How to make one Android class wait for another class to complete its task?

How to make one Android class wait for another class to complete its task?… here is a solution to the problem.

How to make one Android class wait for another class to complete its task?

I’m writing an Android messaging app where one class is calling another class and I want the calling class to wait for the called class to finish before continuing.

Call the MessageManagement code fragment as follows:

private static Messenger myMessenger;

try {
  Message msg = Message.obtain();
  msg.arg1 = constructedMessage.length();
  msg.arg2 = -1;
  msg.obj = constructedMessage;
  Log.d(TAG, "Calling myMessenger.send()");
  myMessenger.send(msg);
  Log.d(TAG, "Sent");
} catch (Exception e) {
  e.printStackTrace();
}
 Wait here until myMessenger completes its task
doOtherStuff();

Now, doOtherStuff() starts and finishes before myMessenger starts. I need myMessenger to finish before doOtherStuff() starts.

I’ve read about wait() and notify(), but I’m not sure how to implement it here, or if it’s the right choice.

Some background on the flow of the program. It’s basically a messaging app that I inherited, so I’m not too sure about its framework. As far as I know, the flow of tracking code:

  1. When a text message is received, the SMS receiver BroadcastReceiver (SmsReceiver) processes it, gets the sender address and message body, and then calls the SMS handler service (HandleSmsService), which then calls a runnable caller class that contains the following following code:

Handling SMS services

public class HandleSmsService extends Service {
  private String message;
  private MessageManagement messageManager;
  private Handler timeoutHandler = new Handler();

@Override
  public void onStart(Intent intent, intent startid) {
    message = intent.getExtras().getString("message");
    messageManager = new MessageManagement(this);
    timeoutHandler.postDelayed(runnable, 10);
  }

private Runnable runnable = new Runnable() {
    @Override
    public void run() {
      try {
        messageManager.handleMessage(message);
        stopSelf();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  };

MessageManagement is

my caller class, and MessageManagement.handleMessage() is the topmost piece of code described earlier.

MessageManagement.handleMessage() apparently calls another handler in the called class when it calls myMessenger.send(msg). The Handler code is as follows:

private Handler smsHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
     do some stuff
  }
};

Solution

I assume that the published code runs on MainThread, and the reason you use the handler is that some asynchronous operation is completed on another thread when the message is received.
In this case, you cannot use wait on a thread because it locks the UI and can cause the application not to respond to errors.

One way to do without changing too much code is to nest a listener in your constructedMessage, for example

public class DoStuffRequest {
    private OnFinishListener mOnFinishListener;
    private boolean isCanceled;
    private String mMessage;
    public interface OnFinishListener {
        public void onFinish();
    }

public DoStuffRequest(String message) {
        mMessage = message;
    }        

public OnFinishListener getOnFinishListener() {
        return mOnFinishListener;
    }

public void setOnFinishListener(OnFinishListener onFinishListener) {
        mOnFinishListener = onFinishListener;
    }

public void cancel() {
        isCanceled = true;
    }

public void notifyFinish() {
        if (!isCanceled && mOnFinishListener != null) {
            mOnFinishListener.onFinish();
        }
    }

public String getMessage() {
        return mMessage;
    }
}

Then use some along this line to get the ball rolling :

private static Messenger myMessenger;
private DoStuffRequest mRequest;
...

private void send(String message) {
    mRequest = new DoStuffRequest(message);    
    mRequest.setOnFinishListener(new ConstructedMessage.OnFinishListener() {
        @Override
        public void onFinish() {
            doOtherStuff();
        }
    });
    try {
        Message msg = Message.obtain();
        msg.arg1 = constructedMessage.length();
        msg.arg2 = -1;
        msg.obj = constructedMessage;
        Log.d(TAG, "Calling myMessenger.send()");
        myMessenger.send(msg);
        Log.d(TAG, "Sent");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void doThisIfYouWantToCancel() {
    if (mRequest != null) {
        mRequest.cancel();
    }
}

When the asynchronous operation completes, your handler/service code can now call constructedMessage.finish(). Depending on what doOtherStuff() does (e.g., when manipulating the UI), you might want to do this on MainThread (the code I wrote above is not thread-safe, I’m assuming you’re calling the listener on MainThread).
Remember to call constructedMessage.cancel() in case you don’t want to be notified anymore (for example, you want to leave Activity/fragment).

This is just one method, and depending on your needs, some other methods may be better options.

Related Problems and Solutions