简体   繁体   中英

How to make an Android class wait until another class completes its task?

I'm writing an Android messaging application, and 1 class is calling another class, and I wish for the calling class to wait for the callee class to complete before carrying on.

Caller Class (MessageManagement) code snippet is 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();

Right now, doOtherStuff() starts and finishes before myMessenger starts. I need myMessenger to complete before doOtherStuff() starts.

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

Some background about the flow of the program. It's basically a messaging app that I inherited, so I'm not exactly sure of its framework. From what I can tell tracing the flow of the code:

  1. When an SMS message is received, the SMS receiver BroadcastReceiver(SmsReceiver) handles it, getting the sender address and message body, then calling a SMS handler service(HandleSmsService), which then calls the caller class in a runnable with the following code:

HandleSmsService

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 top most code snippet presented earlier.

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

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

I'm assuming the posted code is running on the MainThread and the reason why you are using a handler is that something asynchronous is done on another thread when receiving that message. In that case, you can't use wait on the thread, as it will lock up the UI and probably cause an application not responding error.

Without changing too much of your code, one way to do it is to nest a listener in your constructedMessage for eg

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 the line of this 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();
    }
}

your Handler/Service code can now call constructedMessage.finish() when the async stuff is done. Depending on what doOtherStuff() does (eg when manipulating the UI), you might want to do this on the MainThread (the code i've written above is NOT thread safe and i assume you are calling the listener on the MainThread). Also remember to call constructedMessage.cancel() in case you do not want to get notified any more (eg you are leaving the activity/fragment).

this is just one way to do it, depending on your needs, some other methods might be a better choice.

I guess it should look something like this:

    try {
      Message msg = Message.obtain(handler, new Runnable() {

              @Override
              public void run() {
                  doOtherStuff();
              }
        });
      msg.arg1 = constructedMessage.length();
      msg.arg2 = -1;
      msg.obj = constructedMessage;
      Log.d(TAG, "Calling myMessenger.send()");
      msg.sendToTarget();
      Log.d(TAG, "Sent");
    } catch (Exception e) {
      e.printStackTrace();
    }

The other way to do this using native means:

private static Messenger myMessenger = new Messenger(new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message msg) {
        // do something what you need
        if (msg.getTarget() != null) {
            msg.sendToTarget();
        }
        return false;
    }
}));

try {
    final Message msg = Message.obtain();
    msg.setTarget(new Handler(new Handler.Callback() {

        @Override
        public boolean handleMessage(Message msg) {
            doOtherStuff();
            return false;
        }
    }));
    msg.arg1 = constructedMessage.length();
    msg.arg2 = -1;
    msg.obj = constructedMessage;
    Log.d(TAG, "Calling myMessenger.send()");
    myMessenger.send(msg);
    Log.d(TAG, "Sent");
} catch (final Exception e) {
    e.printStackTrace();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM