安卓:正确的方式来传递从后台线程一个消息给UI线程? [英] Android: proper way to pass a message from background thread to UI thread?

查看:225
本文介绍了安卓:正确的方式来传递从后台线程一个消息给UI线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读了很多关于线程,处理程序,尺蠖等,我非常困惑。在我的软件,我想有第一个活动启动一个后台工作。这个后台工作将继续从TCP套接字请求数据和(希望)张贴到UI线程的新信息的数据到达。如果用户转换到一个新的活动背景需要继续做下去的事情,但只发送不同的消息到UI线程,因此它可以相应地更新新的布局。

I have been reading a lot about threads, handlers, loopers, etc and I am very confused. In my app I want to have the first Activity start a background worker. This background worker will continually request data from a TCP socket and (hopefully) post the new info to the UI thread as the data arrives. If the user transitions to a new Activity the background needs to keep doing it's thing but only send different messages to the UI thread so it can update the new layout accordingly.

这是我迄今为止...这是我的主要活动文件

here is what i have so far...This is in my main activity file

public class MyTCPTest extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // set the layout
        setContentView(R.layout.main);
        // create a handler to handle messages from bg thread
        Handler handler = new Handler();

        BgWorkerThread bgw = new BgWorkerThread();
        bgw.start();
 }

在另一个文件中我这样定义我的背景工作者线程...

in another file i define my background worker thread like this...

public class BgWorkerThread extends Thread {    
@Override
public void run(){

    while(true)
    {
        try {
        // simulate a delay (send request for data, receive and interpret response) 
        sleep(1000);

                    // How do I send data here to the UI thread?

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
} 

如果用户界面切换到不同的活动将在线程保持运行?此外,如何在这个线程知道将消息发送给哪些活动?很显然,我希望它永远将数据发送到活动当前处于活动状态。这是否自动发生?

If the UI switches to a different Activity will this thread remain running? Also, how does the this thread know which activity to send the message to? Obviously I want it to always send the data to the Activity that is currently active. Does that happen automatically?

最后,当UI切换到一个不同的活动的bgworker需要通知,以便它可以开始请求相关的数据到新的活动的布局。什么是通知变更的工人最好的方法是什么?我不能只是建立在BgWorkerThread类中的公共方法可以被称为当活动负载?

Finally, when the UI switches to a different activity the bgworker needs to be notified so that it can begin requesting data that is relevant to the new Activity layout. What is the best way to inform the worker of the change? Couldn't I just create a public method in the BgWorkerThread class that could be called when Activities load?

推荐答案

我已经说明了同样的code和以下的太问题。总之,为了通知你的用户界面,并给它不同的情况下,我建议如下:

I've illustrated the same code and a more detailed steps in the followingSO Question. To summarize, in order to notify your UI and give it different context, I suggest the following:

  • 有映射的requestId到处理程序映射(假设你有请求ID的情况下)。你会注册相应的处理程序中的活动因此你可以有处理程序不同的表现每项活动(如更新各种UI元素,当它收到来自服务器的响应)
  • 更改到的AsyncTask的线程模型,因为它有 onProgressUpdate 方法,该方法可以更容易地code以通知从后台线程UI线程
  • Have a map that map requestId to a Handler (assuming you have the context of request id). You would register appropriate Handler in the Activity thus you could have the handlers behave differently for each Activity (e.g. updating various UI elements when it received the response from the server)
  • Change to AsyncTask for Threading Model as it has onProgressUpdate method that makes it easier to code in order to notify the UI Thread from the Background Thread

下面是存根/伪code为您BackgroundThread

Here is the stub/pseudocode for your BackgroundThread

public class ResponseHandler extends AsyncTask<Void, String, Integer> {
    boolean isConnectionClosed = false;
    Map<Integer, Handler> requestIdToMapHandler;

    public ResponseHandler() {
        this.requestIdToMapHandler = new HashMap<Integer, Handler>();
    }

    @Override
    protected Integer doInBackground(Void... params) {
        int errorCode = 0;

        try {
            // while not connection is not close
            while(!isConnectionClosed){
                // blocking call from the device/server
                String responseData = getResponse();

                // once you get the data, you publish the progress
                // this would be executed in the UI Thread
                publishProgress(responseData);
            }
        } catch(Exception e) {
            // error handling code that assigns appropriate error code
        }

        return errorCode;

    }

    @Override
    protected void onPostExecute(Integer errorCode) {
        // handle error on UI Thread
    }

    @Override
    protected void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);
        String responseData = values[0];

        // the response contains the requestId that we need to extract
        int requestId = extractId(responseData);

        // next use the requestId to get the appropriate handler
        Handler uiHandler = getUIHandler(requestId);

        // send the message with data, note that this is just the illustration
        // your data not necessary be jut String
        Message message = uiHandler.obtainMessage();
        message.obj = responseData;
        uiHandler.sendMessage(message);
    }

    /***
     * Stub code for illustration only
     * Get the handler from the Map of requestId map to a Handler that you register from the UI
     * @param requestId Request id that is mapped to a particular handler
     * @return
     */
    private Handler getUIHandler(int requestId) {
        return null;
    }

    /***
     * Stub code for illustration only, parse the response and get the request Id
     * @param responseId
     * @return
     */
    private int extractId(String responseId) {
        return 0;
    }

    /***
     * Stub code for illustration only
     * Call the server to get the TCP data. This is a blocking socket call that wait
     * for the server response
     * @return
     */
    private String getResponse() {
        return null;
    }
}

这篇关于安卓:正确的方式来传递从后台线程一个消息给UI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆