java - Android 将数据从主 UI 线程发送到另一个线程

标签 java android multithreading sockets android-asynctask

我需要将一些数据从主线程发送到另一个线程。我已经阅读了很多关于线程、异步任务和处理程序的资料,但也许它们让我有些困惑。我读到我需要为我的“第二个线程”创建一个处理程序,以便我可以从主线程向它发送消息(现在我不担心将任何东西发回主线程)。

我需要第二个线程连接到服务器(通过套接字)并在某些用户事件上发送一些日期。我正在尝试以有效的方式进行操作(不要打开/关闭不必要的套接字连接)。所以我想知道我应该把 open socket 命令放在哪里?此外,在我的处理程序的 handleMessage() 方法中,我需要引用套接字输出流才能将数据发送到服务器。

我目前有以下代码:

protected void initThread(){
    this.thread = new HandlerThread(WorkerHandler.class.getCanonicalName()){        

        @Override
        public void run() {
            super.run();
            try{
                handler = new WorkerHandler(getLooper());
            }catch(Exception e){
                e.printStackTrace();
            }               
        }

    };
    this.thread.start();
}

在我的 Activity 的 onCreate() 方法中调用了 initThread() 方法。

下面是我的自定义处理程序类的代码:

public class WorkerHandler extends Handler {

protected Socket socket;
protected BufferedWriter writer;

public WorkerHandler(Looper looper) throws Exception{
    super(looper);      
    this.socket = new Socket("192.168.1.7", 5069);
    this.writer = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream(), "utf-8"));

}

public BufferedWriter getWriter(){
    return this.writer;
}

public Socket getSocket(){
    return this.socket;
}

@Override
public void handleMessage(Message msg) {
    Draw draw = (Draw) msg.obj;
    if (draw != null){          
        if (getWriter() != null){
            try{
                getWriter().write(DrawUtil.toJson(draw)+"\n");
                getWriter().flush();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

再次,在我的 Activity 中,我触发了 sendDataToServer() 方法

protected void sendDataToServer(){
    Draw draw = new Draw(getFlowType(), getID(), getSeq(), Calendar.getInstance(), startX, startY, endX, endY);
    if (getWorkerHandler() != null){
        Message msg = getWorkerHandler().obtainMessage();
        msg.obj = draw;
        getWorkerHandler().sendMessage(msg);
    }       
}

但是我对 WorkerHandler 对象的引用始终为空。我很确定我误解了一些概念......你能给我一些提示吗?

非常感谢!

最佳答案

你不能这样做。您已经使用 HandlerThread 创建了第二个线程。 HandlerThread 是具有 LooperThread。这就是 HandlerThreadrun() 方法中发生的事情。它正在运行 looper 循环。这意味着 HandlerThread 中的 run() 方法只会在 Looper 退出时完成。

在您的 initThread() 方法中,您编写了:

    @Override
    public void run() {
        super.run(); // <-- This call runs the Looper loop and doesn't complete!!
        try{
            handler = new WorkerHandler(getLooper());
        }catch(Exception e){
            e.printStackTrace();
        }               
    }

您可以看到您重写的 run() 方法首先调用了 super.run()。这会运行 looper 循环但不会完成。因此 initThread() 中的其余代码永远不会执行。

如果您想使用HandlerThread(),那么您不能乱用它的run() 方法。如果你想让它为你做事,那么你需要向它发送消息(或 Runnable),然后在那里做你的工作。这是一个例子:

    HandlerThread handlerThread = new HandlerThread("myHandlerThread");
    handlerThread.start();
    // Now get the Looper from the HandlerThread so that we can create a Handler that is attached to
    // the HandlerThread
    // NOTE: This call will block until the HandlerThread gets control and initializes its Looper
    Looper looper = handlerThread.getLooper();
    // Create a handler attached to the background message processing thread
    handler = new Handler(looper, this);

现在您可以将消息和 Runnable 发送到“处理程序”。在此示例中,消息将由创建类的重写 handleMessage() 方法处理。

编辑:提供处理程序回调的代码示例

如果你这样修改它,你可以使用你的 WorkerHandler 类来处理回调(我已经将名称更改为 Worker 因为它不是一个真正的 Handler,它只是实现了Handler.Callback接口(interface)):

public class Worker implements Handler.Callback {

    protected Socket socket;
    protected BufferedWriter writer;

    public Worker() throws Exception{    
        this.socket = new Socket("192.168.1.7", 5069);
        this.writer = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream(), "utf-8"));
    }

    public BufferedWriter getWriter(){
        return this.writer;
    }

    public Socket getSocket(){
        return this.socket;
    }

    @Override
    public void handleMessage(Message msg) {
        Draw draw = (Draw) msg.obj;
        if (draw != null){          
            if (getWriter() != null){
                try{
                    getWriter().write(DrawUtil.toJson(draw)+"\n");
                    getWriter().flush();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

现在您需要创建此 Worker 类的实例,并在创建 Handler 时将其作为回调参数传递。在您的 Activity 中:

    HandlerThread handlerThread = new HandlerThread("myHandlerThread");
    handlerThread.start();
    Looper looper = handlerThread.getLooper();
    // Create an instance of the class that will handle the messages that are posted
    //  to the Handler
    Worker worker = new Worker();
    // Create a Handler and give it the worker instance to handle the messages
    handler = new Handler(looper, worker);

关于java - Android 将数据从主 UI 线程发送到另一个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20054864/

相关文章:

java - 使用 BufferedReader 在 java 中获取输入

Java通过数组访问对象

java - 空 Guava 缓存大小?

android - 如何将消息从 Activity 发送到服务并在服务运行时执行?

c++ - 多线程应用程序中注入(inject)的 mprotect 调用的切换标志

JavaFX Gradle 构建错误,java.util.zip.ZipException : duplicate entry: META-INF/LICENSE

android - 移动设备上显示的网页发生了变化和压缩(与桌面浏览器的区别)

android - 不能在应用程序类中同时使用通用图像加载器和 Volley 图像加载器

Linux:信号对多线程的影响

multithreading - 有没有办法让管道从多个来源获取数据而不阻塞其中任何一个?