Невозможно создать обработчик внутри потока, который не вызвал Looper.prepare ()


81

У меня есть Activity, и у меня есть класс.

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

в моем DynamicText java у меня есть этот код:

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 02

Ответы:


146

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

Скорее всего, вы вообще не хотите напрямую создавать экземпляр Handler ... любые данные, которые ваша 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
Ответ абсолютно правильный. Однако в моем случае мне просто пришлось удалить несколько тостов (попытка запуска в потоке пользовательского интерфейса) из моего пользовательского класса FtpUpload AsyncTask и вуаля.
Джош

такая же ошибка приходит ко мне, я не понимаю, как ее решить, я читаю описание, но не понимаю, как это сделать, кто-нибудь может дать мне фрагмент кода, пожалуйста
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. Благодаря!
IgorGanapolsky

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.