Android send data from main UI thread to another thread

android, android-asynctask, java, multithreading, sockets

Solution

You can't do it this way. You've created your second Thread by using `HandlerThread`. A `HandlerThread` is a `Thread` that has a `Looper`. So that is what is going on in the `run()` method of `HandlerThread`. It is running the looper loop. That means that the `run()` method in the `HandlerThread` will only complete when the `Looper` exits.

In your `initThread()` method you wrote:

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

You can see that your overridden `run()` method first calls `super.run()`. This runs the looper loop and doesn't complete. So the rest of your code in `initThread()` never executes.

If you want to use a `HandlerThread()` then you can't mess with its `run()` method. If you want it to do stuff for you then you'll need to post messages (or `Runnable`s) to it, and do your work there. Here's an example:

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

Now you can post messages and `Runnable`s to the "handler". In this example, the messages will be processed by an overridden `handleMessage()` method of the creating class.

EDIT: Provide code example for the Handler callback

You can use your `WorkerHandler` class to handle the callbacks if you modify it like this (I've changed the name to `Worker` because it isn't really a `Handler`, it just implements the `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();
                }
            }
        }
    }
}

Now you need to create an instance of this `Worker` class and pass it as the callback argument when you create the `Handler`. In your activity do:

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

Problem

I need to send some data from the main thread to another thread. I've already read a lot of materials on threads, asynctasks and handlers but maybe they created some confusion to me. I read that I need to create a Handler to my 'second thread' so that I can send messages from the main thread to it (for now I'm not worrying about send back anything to the main thread). I need the second thread to connect to a server (via socket) and send some date on some user events. I'm trying to do it in an efficiently manner (do not open/close unnecessary socket connections). So I'm wondering where should I put my open socket command? Also, in my handler's handleMessage() method I need a reference to the socket output stream in order to send data to server. I have currently the following code: ``` 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(); } ``` The method initThread() is called in the onCreate() method of my activity. Here follows the code of my custom handler class: ``` 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(); } } } } ``` } And again, in my activity, I trigger the sendDataToServer() method ``` 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); } } ``` But my reference to the WorkerHandler object is always null. I'm pretty sure I misunderstood some concept... Could you please give me some hints? Thanks a lot!

Original source