Не вдається створити обробник усередині потоку, який не викликав Looper.prepare ()


81

Я маю діяльність, і в цьому я маю клас.

text=new Dynamictext(...);
text.setText("txt");

у моєму java DynamicText у мене є такий код:

public void setText(String text) {
    this.text=text;
    new asyncCreateText().execute();
    //this.createText(text);
}

//private Handler handler = new Handler();

private class asyncCreateText extends AsyncTask<Void, Void, Void> 
{
    @Override
    protected Void doInBackground(Void... unused) {
        return null;
    }

    @Override
    protected void onPostExecute(Void unused) {

    }
}

Я отримав:

ПОМИЛКА / AndroidRuntime (5176): Викликано: java.lang.RuntimeException: Не вдається створити обробник усередині потоку, який не викликав Looper.prepare ()

Як я можу усунути цю помилку?

ERROR/AndroidRuntime(5370): java.lang.ExceptionInInitializerError
ERROR/AndroidRuntime(5370):     at com.l.start.DynamicText.setText(DynamicText.java:125)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.initfonts(OpenGLRenderer.java:168)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.init(OpenGLRenderer.java:119)
ERROR/AndroidRuntime(5370):     at com.l.start.OpenGLRenderer.onSurfaceChanged(OpenGLRenderer.java:90)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1120)
ERROR/AndroidRuntime(5370):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:975)

ERROR/AndroidRuntime(5370): Caused by: java.lang.RuntimeException: 
    Can't create handler inside thread that has not called Looper.prepare()
ERROR/AndroidRuntime(5370):     at android.os.Handler.<init>(Handler.java:121)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask$InternalHandler.<init>(AsyncTask.java:421)
ERROR/AndroidRuntime(5370):     at android.os.AsyncTask.<clinit>(AsyncTask.java:152)
ERROR/AndroidRuntime(5370):     ... 6 more

Чи можете ви опублікувати повний стек? Здається, ви викликаєте якийсь метод інтерфейсу з фонового потоку або щось інше.
alexanderblom

1
Це детально пояснить проблему.
mjosh

Відповіді:


146

Помилка сама собою пояснюється ... doInBackground()працює на фоновому потоці, який, оскільки він не призначений для циклу, не підключений до Looper.

Швидше за все, ви взагалі не хочете створювати екземпляр обробника ... будь-які дані, які doInBackground()повертає ваша реалізація, будуть передані, onPostExecute()які працюють у потоці інтерфейсу користувача.

   mActivity = ThisActivity.this; 

    mActivity.runOnUiThread(new Runnable() {
     public void run() {
     new asyncCreateText().execute();
     }
   });

ДОДАТИСЯ ЗА СЛІДОМ СТЕКСТРА, ЯКИ ЗНАЧАЮТЬСЯ В ПИТАННІ:

Схоже, ви намагаєтеся розпочати AsyncTaskз потоку візуалізації GL ... не робіть цього, тому що вони ніколи не будуть Looper.loop(). AsyncTasks дійсно розроблені для запуску лише з потоку інтерфейсу користувача.

Найменшим руйнівним рішенням, мабуть, було б зателефонувати Activity.runOnUiThread()з таким, Runnableщо починається з вас AsyncTask.


1
Відповідь абсолютно правильна. Однак у моєму випадку мені просто довелося видалити деякі Toasts (спроба запуску в потоці інтерфейсу користувача) зі свого користувацького класу FtpUpload AsyncTask та voila.
Джош

та сама помилка приходить до мене, я заплутався, як її вирішити, прочитав опис, але не розумію, як це зробити. Хтось може дати мені фрагмент коду, будь ласка
Android - це все для мене

32

Усі відповіді вище є правильними, але я думаю, що це найпростіший приклад:

public class ExampleActivity extends Activity {
    private Handler handler;
    private ProgressBar progress;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        handler = new Handler();
    }

    public void clickAButton(View view) {
        // Do something that takes a while
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                handler.post(new Runnable() { // This thread runs in the UI
                    @Override
                    public void run() {
                        progress.setProgress("anything"); // Update the UI
                    }
                });
            }
        };
        new Thread(runnable).start();
    }
}

Це робить оновлення індикатора прогресу в потоці інтерфейсу користувача із зовсім іншого потоку, пропущеного через метод post () обробника, оголошеного в діяльності.

Сподіваюся, це допоможе!


22

Ви створюєте обробник у фоновому потоці таким чином

private void createHandler() {
        Thread thread = new Thread() {
          public void run() {
               Looper.prepare();

               final Handler handler = new Handler();
               handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                       // Do Work
                        handler.removeCallbacks(this);
                        Looper.myLooper().quit();
                   }
                }, 2000);

                Looper.loop();
            }
        };
        thread.start();
    }

Не тільки вирішує проблему, але й дуже пояснює. Невелике проблемне тісто. Як зміниться структура, якщо це потрібно removeCallbacksі quitколи Workце зроблено, але не досягнуто затримки. Оскільки робота може тривати довше заздалегідь визначеної затримки.
Фарід

12

Activity.runOnUiThread()не працює для мене. Я вирішив цю проблему, створивши звичайний потік таким чином:

public class PullTasksThread extends Thread {
   public void run () {
      Log.d(Prefs.TAG, "Thread run...");
   }
}

і викликати це з оновлення GL таким чином:

new PullTasksThread().start();

Це рішення спрацювало для мене, зателефонувавши йому з GL, але ви повинні бути впевнені, що не викликаєте метод Toasts on run !! AsyncTask не працював, викликаючи це з GL. Дякую!
Альберто М.

Мені чудово підходить для заміни AsyncTask. Дякую!
Ігор Ганапольський

5

Спробуйте запустити асинтаск із потоку інтерфейсу користувача. Я зіткнувся з цією проблемою, коли не робив того самого!


3

Спробуйте це

    Handler mHandler = new Handler(Looper.getMainLooper());
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
 //your code here that talks with the UI level widgets/ try to access the UI 
//elements from this block because this piece of snippet will run in the UI/MainThread.                                     
                            }
                        });

1
Спробуйте додати невелике пояснення. Відповіді лише на код не дуже вдячні для SO.
Олексій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.