如何使Android类等到另一个类完成其任务?

时间:2014-05-08 02:56:01

标签: java android wait notify

我正在编写一个Android消息传递应用程序,并且有一个类正在调用另一个类,我希望调用类在继续之前等待被调用者类完成。

来电者类(MessageManagement)代码段如下:

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();

现在,doOtherStuff()在myMessenger启动之前启动并完成。我需要在doOtherStuff()启动之前完成myMessenger。

我已经阅读过wait()和notify(),但我不确定如何在此处实施,或者它是否是正确的选择。

关于程序流程的一些背景知识。它基本上是我继承的消息传递应用程序,所以我不完全确定它的框架。从我可以告诉跟踪代码的流程:

  1. 当收到SMS消息时,SMS接收器BroadcastReceiver(SmsReceiver)处理它,获取发送方地址和消息体,然后调用SMS处理程序服务(HandleSmsService),然后调用具有以下内容的runnable中的调用程序类代码:
  2. 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是我的调用者类,MessageManagement.handleMessage()是前面提到的最重要的代码片段。

    MessageManagement.handleMessage()显然在调用myMessenger.send(msg)时调用callee类中的另一个Handler。此Handler代码如下:

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

2 个答案:

答案 0 :(得分:4)

我假设已发布的代码在MainThread上运行,并且您使用处理程序的原因是在接收该消息时在另一个线程上执行异步操作。 在这种情况下,您不能在线程上使用wait,因为它会锁定UI并可能导致应用程序无响应错误。

在不改变代码的情况下,一种方法是将一个侦听器嵌套在constructMessage中,例如。

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;
    }
}

然后沿着这条线使用一些来推动球:

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();
    }
}

当异步内容完成后,您的处理程序/服务代码现在可以调用constructedMessage.finish()。根据doOtherStuff()的作用(例如操作UI时),您可能希望在MainThread上执行此操作(上面编写的代码不是线程安全的,我假设您在MainThread上调用侦听器)。 如果您不想再收到通知,请记得致电constructedMessage.cancel()。(例如,您要离开活动/片段)。

这只是一种方法,根据您的需要,其他一些方法可能是更好的选择。

答案 1 :(得分:0)

我想它看起来应该是这样的:

    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();
    }

使用本机方式执行此操作的另一种方法是:

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();
}