Где "выйти" с петлителя?
У меня проблема с петлителем. Я звоню looper.prepare()
и после выполнения чего-то все работает нормально. Но если я поверну устройство, я получу исключение при подготовке.
07-12 16:40:09.760: E/activity(15809): java.lang.RuntimeException: Only one Looper may be created per thread
Я пытаюсь выйти из петлителя, но это ничего не делает.
Вот мой 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();
}
Идеи?
2 ответа
Есть два случая для рассмотрения:
(1) Зацикливание потоков, которые вы хотите прожить всю жизнь приложения, и не имеют сильную ссылку на представление (даже неявно)
Цитируя инженера Google, Кристофера Тейта, вы можете просто оставить петлитель там, пока ваше приложение не будет уничтожено, и оно не справится с этим. Вам не нужно беспокоиться об этом.
"Говоря в общих чертах, никогда не выходите () из ваших потоков петлителей. Этот метод существует в основном по историческим причинам и в целях тестирования. В Real Life™ я рекомендую вам продолжать использовать одни и те же потоки петлителей в течение жизни процесса, а не создание / выход из них."
Я использую такой зацикленный поток как многоцелевой HandlerThread и отправляю ему Runnables всякий раз, когда я хочу, чтобы что-то запускалось вне основного потока (UI).
(2) Looper темы, которые имеют ссылку на представление
Это выпадает из рекомендации Кристофера Тейта, потому что это приведет к утечке памяти, например, если вы поверните экран.
(Лучше сделать поток обработчика статичным и использовать слабую ссылку - и вы вернетесь с вариантом № 1)
Чтобы убить его, вы должны выйти из цикла. Для этого вам нужно запустить команду quit в контексте этого потока.
Поэтому создайте сообщение с каким-нибудь int как вашим msg.what, и в вашем handleMessage дождитесь этого int, а когда оно придет - вызовите:
Looper myLooper = Looper.myLooper();
if (myLooper!=null) {
myLooper.quit();
}
И не забудьте обнулить все ссылки на виды и действия.
Отправьте это сообщение об убийстве обработчику из вашей активности onDestroy()
Looper.prepare()
ассоциирует Looper
-экземпляр с потоком, на котором он вызывается, но Looper.quit()
не удаляет эту связь (она просто останавливает механизм отправки сообщений). Итак, когда вы получаете второй звонок Looper.prepare
RuntimeException
брошен
Общая рекомендация - не связывать Looper
экземпляры с AsyncTask
-потоки. Looper
предназначен для передачи сообщений между потоками, но это уже обрабатывается внутри AsyncTask
, так что данные могут быть отправлены между onPreExecute
(Пользовательский интерфейс) -> doInBackground
(Рабочая нить) -> onPostExecute
(Пользовательский интерфейс).