HandlerThread throws RuntimeException Only one Looper may be created per thread - android

This crash report only contains system trace, because it happens in the HandlerThread:
java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:107)
at android.os.Looper.prepare(Looper.java:102)
at android.os.HandlerThread.run(HandlerThread.java:54)
Seems the looper's prepare is called already for the HandlerThread.
I just don't understand why the HandlerThread's run entering again. It only shows the system's java stacktrace.
I tried calling the HandlerThread's start() method multiple times, it throwed java.lang.IllegalThreadStateException, not the RuntimeException.
So when HandlerThread throws such exception?
========================================================
The key code about the HandlerThread and Handler is below:
class MyDeviceFragment extends BaseFragment {
private HandlerThread mWorkerThread = new HandlerThread(MyDeviceFragment .class.getName());
private WorkerHandler mWorkerHandler;
{
if (mWorkerHandler == null) {
mWorkerThread.start();
mWorkerHandler = new WorkerHandler(mWorkerThread.getLooper());
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// xxxxx code
}
public void onDetach() {
super.onDetach();
if (mWorkerThread != null) {
mWorkerThread.quit();
}
}
private class WorkerHandler extends Handler {
WorkerHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_XXXXX1:
synchronized (mLock) {
// CODE
}
break;
case MSG_XXXXX2:
synchronized (mLock) {
// CODE
}
break;
}
}
}
}
And using mWorkerHandler.sendEmptyMessage(MSG_XXX) to send message.
The initialization of mWorkerThread is a little weird, written by third-party, but I don't think it could cause HandlerThread throwing the RuntimeException. Am i right?

I think we can extends HandlerThread
#Override
public void run() {
try {
super.run();
} catch (Exception e) {
LogUtil.e(TAG, "run e =" + e);
}
}
But I have no idea about reason.

Related

getLooper() returns null after started HandlerThread

I have an class extends HandlerThread, it looks like this:
public class MyHandlerThread extends HandlerThread {
private Object lock;
//constructor
public MyHandlerThread() {
super(“MyHandlerThread”);
lock = new Object();
}
public void prepare() {
//starts the handler thread
start();
//Wait for thread starting
Log.d(TAG, "wait for thread starting…");
synchronized (lock) {
try {
lock.wait(5000);
} catch (InterruptedException e) {
Log.e(TAG, "Failed to wait for thread to start");
}
}
//WHY getLooper() returns null here?
if(getLooper() == null) {
Log.d("GET LOOPER NULL!");
}
}
#Override
public void run() {
Log.d("run() begin...");
initializeSomeObjects()
Log.d(“initialise objects done!”);
//Notify that run() finished
synchronized (lock) {
lock.notify();
}
Log.d("run() end!”);
}
}
As you see above, the prepare() function starts the thread & wait for run() to be finished, then try to get looper.
In another class, I create an instance of MyHandlerThread & start it:
MyHandlerThread myThread = new MyHandlerThread();
myThread.prepare();
Logs showing in console:
wait for thread starting…
run() begin...
initialise objects done!
run() end!
GET LOOPER NULL!
Why in prepare() function, call to getLooper() returns null though the thread is already started (run() is executed)?
HandlerThread Looper is initialized in HandlerThread#run().
If you override the method and don't call super.run(), the init code from superclass is not executed.

Android HandlerThread class

I'm using HandlerThread to handle threading in Android,
public class HandlerTest extends HandlerThread {
private static final int MESSAGE_TYPE0 = 0;
private static final String TAG = "TAG";
Handler mHandler;
public interface Listener {
void onHandlerTestDone(String str);
}
#SuppressLint("HandlerLeak")
#Override
protected void onLooperPrepared() {
Log.i(TAG, "OnLoopPrep");
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TYPE0) {
#SuppressWarnings("unchecked")
String msgObj = (String) msg.obj;
handleRequest(msgObj);
}
}
};
}
private void handleRequest(final String token) {
final String str = token;
try {
this.sleep(5000, 0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
handleMessage(token);
}
public void clearQueue() {
mHandler.removeMessages(MESSAGE_TYPE0);
}
}
I have two activities, Activity 1 calls Activity 2, then On activity 2 I do this
HandlerTest hlrtest;
protected void onCreate(Bundle savedInstanceState) {
hlrtest.start();// start looper
hlrtest.getLooper();
hlrtest.PrepMessage("test1"); //will be handled by the thread then
//the thread will go to sleep for 5 second
hlrtest.PrepMessage("test2"); //will be queued
hlrtest.PrepMessage("test3"); //will be queued
hlrtest.PrepMessage("test4"); //will be queued
//Now quit this activity and go back to Activity 1
#Override
public void onDestroy() {
super.onDestroy();
hlrtest.clearQueue();
hlrtest.quit();
}
}
As you can see I make the thread sleep for 5 seconds to simulate that it's getting busy for that amount of time. when I send 4 requests and then I go back to Activity 1 the thread will handle only the first request and the queue will get cleared and the thread will exit as onDestroy() will do that after going back to Activity 1.
If I don't call clearQueue() and quit() in the destroy I will end up with a zombie thread.
How can I send many requests to the thread and I want the thread to handle them all and then quit when the queue is empty?
please note that I don't want to use quitSafely() as it's only supported from sdk 18 and above
You could create another message type that signals the Handler to clean up and quit. Perhaps something like this (untested) code for handleMessage():
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TYPE0) {
#SuppressWarnings("unchecked")
String msgObj = (String) msg.obj;
handleRequest(msgObj);
} else if (msg.what == MESSAGE_TYPE_FINISH) {
mHandler.clearQueue();
mHandler.quit();
}
};

Android: Background thread in Singleton class

I have Singleton class which holds all the data (visitors of some site) and the data is updated by a service. I have an interface, which is implemented by an (list) activity (which shows visitors), so now as I get the data updated, I simply call the interface method so that the list activity can refresh it.
Now I need to maintain the time visitors are on site (at client end). I want to make a thread in Singleton class which will run a loop after every second, but I am not able to call any method on Main thread, using Handlers.
Here's the code of thread:
void startHeavyDutyStuff() {
Thread t = new Thread() {
public void run() {
try {
while(true) {
sleep(1000);
ArrayList<VisitorMC> data = SharedAppManager.appManager().visitorsData;
boolean doReload = false;
for (VisitorMC item: data) {
item.secsOnSite++;
if(item.secsOnSite == 60) {
item.secsOnSite = 0;
item.minsOnSite++;
doReload = true;
}
}
if(doReload) {
messageHandler.sendEmptyMessage(1);
} else {
messageHandler.sendEmptyMessage(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
And here's the code where I am making the Handler on Main Thread (in Singleton class):
private SharedAppManager() {
//Initialization of the data.
Looper.prepare();
messageHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case 0:
Log.d("THREAD", "after every second");
break;
case 1:
if(visitorsDelegate != null) {
visitorsDelegate.updateVisitorsTime();
}
break;
default:
}
}
};
startHeavyDutyStuff();
}
What am I doing wrong here?
Edit:
I need to update the UI after each second, that's why I am running a separate thread which could change the Data and call update on UI.

While Loop inside Thread not working?

I have a very simple UI and i need to constantly run a check process, so I am trying to use a Thread with a while loop.
When I run the loop with nothing but a Thread.sleep(1000) command, it works fine, but as soon as I put in a display.setText(), the program runs for a second on the emulator then quits. I cannot even see the error message since it exits so fast.
I then took the display.setText() command outside the thread and just put it directly inside onCreate, and it works fine (so there is no problem with the actual command).
here is my code, and help will be greatly appreciated.
Thank you!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
You can't update the UI from a non-UI thread. Use a Handler. Something like this could work:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
You could also avoid a Handler for this simple case and just use
while (boo) {
runOnUiThread(updater);
// ...
Alternatively, you could use an AsyncTask instead of your own Thread class and override the onProgressUpdate method.
Not 100% certain, but I think it is a case of not being able to modify UI controls from a thread that did not create them?
When you are not in your UI thread, instead of display3.setText("test") use:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
You should encapsulate this code in an AsyncTask instead. Like so:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Then just launch the task from your onCreate method.
In non-UI thread,you can't update UI.In new Thread,you can use some methods to notice to update UI.
use Handler
use AsyncTask
use LocalBroadcast
if the process is the observer pattern,can use RxJava

Android 2.2: ProgressDialog Freezing In Second Thread

I have recently experimented with creating an easy way to open a ProgressDialog up in a second thread, so if the main thread freezes the dialog will keep working.
Here is the class:
public class ProgressDialogThread extends Thread
{
public Looper ThreadLooper;
public Handler mHandler;
public ProgressDialog ThreadDialog;
public Context DialogContext;
public String DialogTitle;
public String DialogMessage;
public ProgressDialogThread(Context mContext, String mTitle, String mMessage)
{
DialogContext = mContext;
DialogTitle = mTitle;
DialogMessage = mMessage;
}
public void run()
{
Looper.prepare();
ThreadLooper = Looper.myLooper();
ThreadDialog = new ProgressDialog(DialogContext);
ThreadDialog.setTitle(DialogTitle);
ThreadDialog.setMessage(DialogMessage);
ThreadDialog.show();
mHandler = new Handler();
Looper.loop();
}
public void Update(final String mTitle, final String mMessage)
{
while(mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Update)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadDialog.setTitle(mTitle);
ThreadDialog.setMessage(mMessage);
}});
}
public void Dismiss()
{
while(ThreadDialog == null || mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Dismiss)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadDialog.dismiss();
}});
}
public void Continue()
{
while(ThreadLooper == null || mHandler == null)
synchronized(this) {
try { wait(10); }
catch (InterruptedException e) {
Log.d("Exception(ProgressDialogThread.Continue)", e.getMessage() == null ? "MISSING MESSAGE" : e.getMessage());
}
}
mHandler.post(new Runnable(){
#Override
public void run() {
ThreadLooper.quit();
}});
}
However it sometimes work perfectly but other times the application simply freezes and crashes eventually.
Here is an example of use:
ProgressDialogThread thread = new ProgressDialogThread(this, "Loading", "Please wait...");
thread.start();
// Do Stuff
thread.Dismiss();
thread.Continue();
It generates a lot of warning and even some crashes sometimes:
eg.
Handler: Sending message to dead thread....
and exceptions like
ANR in ......
Reason: keyDispatchingTimedOut
Thanks for any help,
Alex.
When wanting to do stuff in separate threads on Android, you should look at the AsyncTask class. You can read about it here: http://developer.android.com/resources/articles/painless-threading.html
Googling (or searching here on Stack Overflow) will also give you plenty of information on how to use it it the above link isn't sufficient :)

Categories

Resources