Nie można utworzyć programu obsługi wewnątrz wątku, który nie wywołał Looper.prepare ()


81

Mam aktywność, w której mam zajęcia.

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

w mojej java DynamicText mam ten kod:

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) {

    }
}

Dostaję:

BŁĄD / AndroidRuntime (5176): spowodowane przez: java.lang.RuntimeException: nie można utworzyć modułu obsługi wewnątrz wątku, który nie wywołał Looper.prepare ()

Jak mogę sobie poradzić z tym błędem?

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

Czy możesz opublikować pełny ślad stosu? Wygląda na to, że wywołujesz jakąś metodę interfejsu użytkownika z wątku w tle lub coś w tym stylu.
— alexanderblom

1
To szczegółowo wyjaśni problem.
— mjosh

Odpowiedzi:


146

Błąd jest oczywisty ... doInBackground()działa w wątku w tle, który, ponieważ nie jest przeznaczony do zapętlenia, nie jest podłączony do Looper.

Najprawdopodobniej w ogóle nie chcesz bezpośrednio tworzyć instancji programu obsługi ... wszelkie dane zwrócone przez Twoją doInBackground()implementację zostaną przekazane, onPostExecute()które działają w wątku interfejsu użytkownika.

   mActivity = ThisActivity.this; 

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

DODANO WEDŁUG ŚLADU STOSU POJAWIAJĄCEGO SIĘ W PYTANIU:

Wygląda na to, że próbujesz rozpocząć AsyncTaskod wątku renderującego GL ... nie rób tego, bo oni też nigdy nie będą Looper.loop(). AsyncTasks są tak naprawdę zaprojektowane do uruchamiania tylko z wątku interfejsu użytkownika.

Najmniej uciążliwą poprawką byłoby prawdopodobnie wezwanie Activity.runOnUiThread()osoby, Runnablektóra uruchomi Twój AsyncTask.


1
Odpowiedź jest całkowicie poprawna. Jednak w moim przypadku musiałem tylko usunąć niektóre Toasty (próbując uruchomić w wątku interfejsu użytkownika) z mojej niestandardowej klasy FtpUpload AsyncTask i voila.
— Josh

zbliża się do mnie ten sam błąd, jestem zdezorientowany, jak go rozwiązać, czytam opis, ale nie rozumiem, jak to zrobić, czy ktoś może dać mi fragment kodu, proszę
— Android jest dla mnie wszystkim

32

Wszystkie powyższe odpowiedzi są poprawne, ale myślę, że jest to najprostszy możliwy przykład:

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();
    }
}

To powoduje aktualizację paska postępu w wątku interfejsu użytkownika z zupełnie innego wątku przekazanego przez metodę post () procedury obsługi zadeklarowanej w działaniu.

Mam nadzieję, że to pomoże!


22

W ten sposób tworzysz procedurę obsługi w wątku w tle

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();
    }

Nie tylko rozwiązuje problem, ale także bardzo wyjaśnia. Ciasto z niewielkimi problemami. Jak zmieni się struktura, jeśli zechcesz removeCallbacksi quitkiedy Workzostanie to zrobione, ale nie nastąpi opóźnienie. Ponieważ praca może trwać dłużej niż wstępnie zdefiniowane opóźnienie.
— Farid

12

Activity.runOnUiThread()nie działa dla mnie. Omówiłem ten problem, tworząc zwykły wątek w ten sposób:

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

i wywołując go z aktualizacji GL w ten sposób:

new PullTasksThread().start();

To rozwiązanie zadziałało, gdy dzwoniłem z GL, ale musisz być pewien, że nie wywołujesz metody Toasts on run !! AsyncTask nie zadziałał wywołując go z GL. Dzięki!
— Alberto M.

Działa świetnie dla mnie w zastępowaniu AsyncTask. Dzięki!
— IgorGanapolsky

5

Spróbuj uruchomić swoje zadanie jako zadanie z poziomu wątku interfejsu użytkownika. Zmierzyłem się z tym problemem, kiedy nie robiłem tego samego!


3

Spróbuj tego

    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
Spróbuj dodać małe wyjaśnienie. Odpowiedzi zawierające tylko kod nie są bardzo cenione w SO.
— Alexei
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.