简体   繁体   English

如何在Java中从主线程调用线程的方法

[英]How to call a thread's method from main thread in java

I start a thread runnable within my Android code and it performs a task continually in a TimerTask until stopTimerTask() is called. 我在Android代码中启动了一个可运行的线程,该线程在TimerTask中连续执行任务,直到调用stopTimerTask()为止。 I'd like to call the stopTimerTask() method in the thread from the main (UI) thread. 我想从主(UI)线程中调用stopTimerTask()方法。 I start the thread like so. 我这样启动线程。

 public void test() {
        new Thread(runWaitResponseProcedure).start();
    }

    Runnable runWaitResponseProcedure = new Runnable() {
        startTimer();
    }

Please note that I definitely need to call this method from the UIThread. 请注意,我绝对需要从UIThread调用此方法。

If your UI thread has a reference to a Thread or Runnable object, then it can invoke any method of that object just as it does a method of any other object. 如果您的UI线程引用了ThreadRunnable对象,则它可以调用该对象的任何方法,就像调用其他任何对象的方法一样。 The method will run in the invoking thread. 该方法将在调用线程中运行。

On the other hand, if you want a method to run in some specific thread then you must arrange for that thread to invoke it. 另一方面,如果要使方法在某个特定线程中运行,则必须安排该线程来调用它。 You might do that, for instance, by raising a flag on the Runnable object in use by the target thread (which flag you must make available by defining it on a Runnable implementation class), and having instances of that class periodically test that flag to determine whether to invoke the method in question. 例如,您可以通过在目标线程正在使用的Runnable对象上引发一个标志(必须通过在Runnable实现类上对其进行定义来使该标志可用)并让该类的实例定期测试该标志来做到这一点确定是否调用有问题的方法。 Be sure to properly synchronize all accesses from such a flag. 确保正确同步来自该标志的所有访问。

On a side note, I observe that the anonymous Runnable implementation class in your sample code does not do anything like what you describe. 附带一提,我注意到示例代码中的匿名Runnable实现类并没有执行您所描述的任何操作。 It simply runs the startTimer() method of the outer class, once, then finishes. 它仅运行一次外部类的startTimer()方法,然后运行一次。

I have used handlers/messengers to send messages from a thread that would invoke methods in my GUI. 我已经使用处理程序/消息传递程序从将在GUI中调用方法的线程发送消息。 I'm sure you could reverse what I did and invoke methods in your runnable. 我确定您可以颠倒我所做的事情,并在您的runnable中调用方法。

In the thread class you would define the following: 在线程类中,您将定义以下内容:

public class UpdaterHandler extends Handler{
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case 1:
                Bundle data = msg.getData();
                String update = data.getString("COMMAND");
                if(update.equals("STOP"){
                    stopTimer();
                break;

            default:
                super.handleMessage(msg);
                break;
        }

    }
}

Notes: msg.what contains an integer that you get to set like a tag in the main GUI. 注意:msg.what包含一个整数,您可以像在主GUI中的标记一样进行设置。 There could possibly be other messages flying through but the int 1 indicates its a message you sent. 可能还有其他消息飞过,但int 1表示它是您发送的消息。 data.getString("COMMAND") --> The string command is the key that you gave for you data. data.getString(“ COMMAND”)->字符串命令是您为数据提供的密钥。 You can make it whatever you want. 您可以随心所欲。

You'll need the following instance variables in your thread: 您的线程中将需要以下实例变量:

private UpdaterHandler handler = new UpdaterHandler();
private Messenger messenger = new Messenger(handler);

Now the messenger object you just made needs to get passed back to the UI. 现在,您刚刚创建的Messenger对象需要传递回UI。 So in the constructor of your thread should probably be something like: 因此,在线程的构造函数中,可能应该是这样的:

MyThreadClass(Context context){
((YourActivityClass)context).setMessenger(messenger)
....
}

This will give you the messenger in your UI 这将为您提供UI中的Messenger

Now in your UI: 现在在您的用户界面中:

Message message;

stopTimerButton.setOnclickListener ..... {
      message = Message.obtain();
      bundle = new Bundle();
      bundle.putString("COMMAND", "STOP");
      message.setData(bundle);
      message.what = 1;
      messenger.send(message);
}

Note the messenger here is the one that gets set with setMessenger(...) that you called from the thread. 请注意,这里的Messenger是使用您从线程调用的setMessenger(...)设置的。

Now when you push the stop button in the UI it creates a new message object, stuff it with a command, then gives it to the messenger which you sent to the UI from the thread. 现在,当您按下UI中的“停止”按钮时,它将创建一个新的消息对象,用命令填充该对象,然后将其提供给您从线程发送到UI的Messenger。 Messenger.send() will automatically send this back to the running thread. Messenger.send()将自动将此发送回正在运行的线程。 In the thread the message gets deconstructed and based on its contents you can do whatever you want. 在线程中,该消息被解构,并且根据其内容,您可以执行任何所需的操作。 In this case you call a stopTimer method within the thread itself. 在这种情况下,您可以在线程本身内调用stopTimer方法。

In my own program I did this in the other direction it will be interesting to see if it works. 在我自己的程序中,我朝另一个方向执行此操作,看看它是否有效将很有趣。 Obviously you can copy and paste some of this code but I didn't fill in everything 显然,您可以复制并粘贴一些此代码,但我没有填写所有内容

-- You could also just interrupt the thread which will just stop it but I don't think that's what you want. -您也可以中断线程,这只会停止它,但我认为这不是您想要的。

change your design pattern,problem can be solved,such as: 改变设计模式,问题可以解决,例如:

 public class RunTimerManager implements Runnable {

public void startTimer() {

}

public void stopTimer() {

}

public void test() {

    new Thread(this).start();

    try {
        wait(10000);
    } catch (Exception e) {
        e.printStackTrace();
    }
    stopTimer();

}

@Override
public void run() {
    // ........
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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