I have a problem with a looper. I call looper.prepare()
, and after doing something it all works fine. But if I rotate the device I get an exception on the prepare.
07-12 16:40:09.760: E/activity(15809): java.lang.RuntimeException: Only one Looper may be created per thread
I'm trying to quit the looper, but it doesn't do anything.
Here is my AsyncTask:
@Override
protected String doInBackground(String... args) {
try{Looper.prepare(); //here start the exception
try {
URL url = new URL(link);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
utente.measure(0, 0);
bmImg = decodeSampledBitmapFromResource(is,(int) utente.getMeasuredWidth(), utente.getMeasuredHeight(), link);
if(bmImg!=null){
try{
getCroppedBitmap();
}catch(Exception e){
System.out.println(e);
}
}
}
catch (IOException e)
{
Log.e("lele", "errore qui");
e.printStackTrace();
}
Looper.myLooper().quit(); //do nothings
}catch(Exception e){
Log.e("canta tu", " "+e);
}
Looper.myLooper().quit(); //do nothings
return null;
}
@Override
protected void onPostExecute(String args) {
//Looper.myLooper().quit(); //generathed an error, main thread can't stop looper
if(bmImg!=null){
try{
utente.setImageBitmap(bmImg);
ellisse.setVisibility(View.VISIBLE);
}catch(Exception e){
Log.e("lele",""+e);
Log.e("lele","errore probabile out of bound");
}
}
else {
Toast.makeText(getApplicationContext(), "Modifica la foto da \"profilo\"", Toast.LENGTH_LONG).show();
}
Ideas?
Be sure to call quit() to end the loop. Quits the looper. Causes the loop() method to terminate without processing any more messages in the message queue.
2. Each thread can have only one Looper.
A thread gets a Looper and MessageQueue by calling Looper. prepare() after its running. Looper. prepare() identifies the calling thread, creates a Looper and MessageQueue object and associate the thread with them in ThreadLocal storage class.
getMainLooper() is convenience API to get looper which is attached to the main thread of the activity.It is usefull when you want to excute some code on main thread from a background thread. It is usually used as follows: new Handler(Looper.getMainLooper()).post(task);
There are two cases to consider:
(1) looper threads you want to live the entire life of the app, and do not hold strong reference to a view (even not implicitly)
Quoting Google engineer, Christopher Tate - you can just leave the looper there until your app is destroyed, and it will go down with it. You don't need to worry about it.
"Speaking very generally, never quit() your looper threads. That method exists mostly for historical and testing reasons. In Real Life™, I recommend that you continue to reuse the same looper thread(s) for the life of the process rather than creating/quitting them."
I use such a looper thread as a multi purpose HandlerThread, and send Runnables to it whenever I want something to run outside the main thread (UI).
(2) looper threads that have reference to a view
This one falls out of the recommendation of Christopher Tate, because it will cause memory leak, for example if you rotate the screen.
(You better make the handler thread static and use weak reference - and you'll be back with option #1)
To kill it you must quit the loop. To do that, you need to run the quit command on the context of that thread.
So create a message with some whatever int as your msg.what, and in your handleMessage wait for this int, and when it arrives - call:
Looper myLooper = Looper.myLooper();
if (myLooper!=null) {
myLooper.quit();
}
And don't forget to null all reference to views and activities.
Send this kill message to the handler from your activity onDestroy()
Looper.prepare()
associates a Looper
-instance with the thread that it is called on, but Looper.quit()
does not remove this association (it merely stops the message dispatch mechanism). So, when you get a second call to Looper.prepare
a RuntimeException
is thrown.
The general recommendation is to not associate Looper
-instances with AsyncTask
-threads. The Looper
is intended for passing messages between threads, but this is already handled internally in the AsyncTask
, so that data can be sent between onPreExecute
(UI thread) -> doInBackground
(Worker thread) -> onPostExecute
(UI thread).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With