Где "выйти" с петлителя?

У меня проблема с петлителем. Я звоню 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 (Пользовательский интерфейс).

Другие вопросы по тегам