I'm trying to get a hang of multi-threading in Android. My aim is to send data from the main thread to a worker thread.
I have a main activity with the following code in its onCreate
-
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadOne threadOne = new ThreadOne();
threadOne.start();
threadOneLooper = threadOne.getLooper();
Message msg = new Message();
msg.obj = "message.";
Log.i("id--(threadOneLooper)", String.valueOf(threadOneLooper.getThread().getId()));
Log.i("id--(Main)", String.valueOf(getMainLooper().getThread().getId()));
TestHandler mHandler = new TestHandler(threadOneLooper);
mHandler.handleMessage(msg);
}
As you can observe, I store a reference of the worker thread's looper in threadOneLooper
and then log the id of its associated thread.
At the same time I also print the id of the main thread.
Following is the code for my thread -
public class ThreadOne extends Thread{
@Override
public void run() {
if (Looper.myLooper() == null)
Looper.prepare();
Log.i("ThreadOne", "run()");
// Just making sure all approaches give the same result
Log.i("Id--Thread id 1", String.valueOf(getLooper().getThread().getId()));
Log.i("Id--Thread id 2", String.valueOf(getId()));
Looper.loop();
}
Looper getLooper() {
if (Looper.myLooper() != null)
return Looper.myLooper();
else
return null;
}
And following is the code of my handler -
public class TestHandler extends Handler {
TestHandler(Looper myLooper) {
super(myLooper);
}
public void handleMessage(Message msg) {
String txt = (String) msg.obj;
Log.i("Handler", txt);
Log.i("Id--(Handler)", String.valueOf(getLooper().getThread().getId()));
}
}
Now, the problem is that I had assumed that the Log.i("Id--(Handler)", String.valueOf(getLooper().getThread().getId()));
statement would log the thread id of ThreadOne
since we are passing the thread's looper into the handler. However, the id being logged is of the main thread. Why is that? Is it correct to assume that handleMessage()
is being executed on the main thread?
The problem is with the getLooper()
method of ThreadOne
. The method returns myLooper() associated with the thread that called the method.
For returning a Looper associated with ThreadOne
I'd suggest the following implementation of the class:
public class ThreadOne extends Thread {
private Looper mLooper = null;
@Override
public void run() {
Looper.prepare();
mLooper = Looper.myLooper();
Looper.loop();
}
Looper getLooper() {
return mLooper;
}
}
Note! The ThreadOne
's Looper is null
until it is running. You cannot get non-null
reference to it earlier. You must check if the thread is running before calling the getLooper()
method.
P.S. You might want to reconsider the approach with getting the ThreadOne
's Looper. Having a Handler associated with ThreadOne
might be enough (see the example of thread).