Kan geen handler maken in thread die Looper.prepare() niet heeft aangeroepen

Wat betekent de volgende uitzondering; hoe kan ik het oplossen?

Dit is de code:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

Dit is de uitzondering:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)

Antwoord 1, autoriteit 100%

Je roept het vanuit een werkthread. Je moet Toast.makeText()(en de meeste andere functies die te maken hebben met de gebruikersinterface) aanroepen vanuit de hoofdthread. Je zou bijvoorbeeld een handler kunnen gebruiken.

Zoek Communiceren met de UI-threadop in de documentatie . In een notendop:

// Set this up in the UI thread.
mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};
void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

Andere opties:

Je zou Activity.runOnUiThread(). Eenvoudig als je een Activityhebt:

@WorkerThread
void workerThread() {
    myActivity.runOnUiThread(() -> {
        // This is where your UI code goes.
    }
}

Je zou ook naar de hoofdlooper kunnen posten. Dit werkt prima als je alleen een Contexthebt.

@WorkerThread
void workerThread() {
    ContextCompat.getMainExecutor(context).execute(()  -> {
        // This is where your UI code goes.
    }
}

Verouderd:

Je zou een AsyncTaskkunnen gebruiken, die voor de meeste dingen goed werkt draait op de achtergrond. Het heeft haken die je kunt aanroepen om de voortgang aan te geven en wanneer het klaar is.

Het is handig, maar kan contexten lekken als het niet correct wordt gebruikt. Het is officieel afgeschaft en je zou het niet meer moeten gebruiken.


Antwoord 2, autoriteit 94%

Je moet Toast.makeText(...)aanroepen vanuit de UI-thread:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});

Dit is gekopieerd en geplakt van een ander (dubbel) SO-antwoord.


Antwoord 3, autoriteit 59%

UPDATE – 2016

Het beste alternatief is om RxAndroid(specifieke bindingen voor RxJava) te gebruiken voor de Pin MVPom neem de leiding over gegevens.

Begin met het retourneren van Observablevan uw bestaande methode.

private Observable<PojoObject> getObservableItems() {
    return Observable.create(subscriber -> {
        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}

Gebruik deze waarneembare op deze manier –

getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
    @Override
    public void onCompleted() {
        // Print Toast on completion
    }
    @Override
    public void onError(Throwable e) {}
    @Override
    public void onNext(PojoObject pojoObject) {
        // Show Progress
    }
});
}

——————————————– ————————————————– ————————————

Ik weet dat ik een beetje laat ben, maar hier komt het.
Android werkt in principe op twee typen threads, namelijk UI-threaden achtergrondthread. Volgens Android-documentatie –

Geef geen toegang tot de Android UI-toolkit van buiten de UI-thread om dit probleem op te lossen. Android biedt verschillende manieren om toegang te krijgen tot de UI-thread vanuit andere threads. Hier is een lijst met methoden die kunnen helpen:

Activity.runOnUiThread(Runnable)  
View.post(Runnable)  
View.postDelayed(Runnable, long)

Er zijn nu verschillende methoden om dit probleem op te lossen.

Ik zal het uitleggen aan de hand van een codevoorbeeld:

runOnUiThread

new Thread()
{
    public void run()
    {
        myactivity.this.runOnUiThread(new Runnable()
        {
            public void run()
            {
                //Do your UI operations like dialog opening or Toast here
            }
        });
    }
}.start();

LOOPER

Klasse die wordt gebruikt om een berichtenlus voor een thread uit te voeren. Discussies doen standaard
er geen berichtenlus aan is gekoppeld; om er een te maken, bel
prepare() in de thread die de lus moet uitvoeren, en vervolgens loop() naar
laat het berichten verwerken totdat de lus wordt gestopt.

class LooperThread extends Thread {
    public Handler mHandler;
    public void run() {
        Looper.prepare();
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };
        Looper.loop();
    }
}

AsyncTask

AsyncTask stelt u in staat asynchroon werk op uw gebruiker uit te voeren
koppel. Het voert de blokkeerbewerkingen uit in een werkthread en
publiceert vervolgens de resultaten op de UI-thread, zonder dat u dat hoeft te doen
behandel threads en/of handlers zelf.

public void onClick(View v) {
    new CustomTask().execute((Void[])null);
}
private class CustomTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... param) {
        //Do some work
        return null;
    }
    protected void onPostExecute(Void param) {
        //Print Toast or open dialog
    }
}

Behandelaar

Met een handler kunt u berichten en uitvoerbare objecten verzenden en verwerken
gekoppeld aan de MessageQueue van een thread.

Message msg = new Message();
new Thread()
{
    public void run()
    {
        msg.arg1=1;
        handler.sendMessage(msg);
    }
}.start();
Handler handler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        if(msg.arg1==1)
        {
            //Print Toast or open dialog        
        }
        return false;
    }
});

Antwoord 4, autoriteit 21%

Toast.makeText()mag alleen worden aangeroepen vanuit de hoofd-/UI-thread. Looper.getMainLooper()helpt u dit te bereiken :

ANDROID

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
        toast.show();
    }
});

KOTLIN

Handler(Looper.getMainLooper()).post {
        Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT).show()
}

Een voordeel van deze methode is dat u UI-code kunt uitvoeren zonder activiteit of context.


Antwoord 5, autoriteit 13%

Probeer dit als u runtimeException ziet omdat Looper niet is voorbereid voor de handler.

Handler handler = new Handler(Looper.getMainLooper()); 
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
  // Run your task here
  }
}, 1000 );

Antwoord 6, autoriteit 6%

Ik kwam hetzelfde probleem tegen en hier is hoe ik het heb opgelost:

private final class UIHandler extends Handler
{
    public static final int DISPLAY_UI_TOAST = 0;
    public static final int DISPLAY_UI_DIALOG = 1;
    public UIHandler(Looper looper)
    {
        super(looper);
    }
    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
        case UIHandler.DISPLAY_UI_TOAST:
        {
            Context context = getApplicationContext();
            Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
            t.show();
        }
        case UIHandler.DISPLAY_UI_DIALOG:
            //TBD
        default:
            break;
        }
    }
}
protected void handleUIRequest(String message)
{
    Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
    msg.obj = message;
    uiHandler.sendMessage(msg);
}

Om de UIHandler te maken, moet u het volgende doen:

   HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

Hopelijk helpt dit.


Antwoord 7, autoriteit 5%

Reden voor een fout:

Worker-threads zijn bedoeld om achtergrondtaken uit te voeren en je kunt niets op de gebruikersinterface binnen een worker-thread laten zien, tenzij je een methode aanroept zoals runOnUiThread. Als u iets op de UI-thread probeert weer te geven zonder runOnUiThread aan te roepen, is er een java.lang.RuntimeException.

Dus, als je in een Activityzit maar Toast.makeText()aanroept vanuit een werkthread, doe dan dit:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 

De bovenstaande code zorgt ervoor dat je het Toast-bericht in een UI threadlaat zien, aangezien je het binnen de runOnUiThread-methode aanroept. Dus geen java.lang.RuntimeExceptionmeer.


Antwoord 8, autoriteit 3%

dat is wat ik deed.

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});

Visuele componenten zijn “vergrendeld” voor wijzigingen van externe threads.
Dus, aangezien de toast dingen op het hoofdscherm laat zien die worden beheerd door de hoofdthread, moet je deze code op die thread uitvoeren.
Ik hoop dat dat helpt 🙂


Antwoord 9, autoriteit 3%

Ik kreeg deze foutmelding totdat ik het volgende deed.

public void somethingHappened(final Context context)
{
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
            }
        }
    );
}

En maakte er een singleton-klas van:

public enum Toaster {
    INSTANCE;
    private final Handler handler = new Handler(Looper.getMainLooper());
    public void postMessage(final String message) {
        handler.post(
            new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
                        .show();
                }
            }
        );
    }
}

Antwoord 10, autoriteit 2%

Prachtige Kotlin-oplossing:

runOnUiThread {
    // Add your ui thread code here
}

Antwoord 11, autoriteit 2%

runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });

Antwoord 12

Dit komt omdat Toast.makeText() aanroept vanuit een werkthread. Het zou een oproep moeten zijn van de hoofd UI-thread zoals deze

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });

Antwoord 13

bel eerst Looper.prepare()en bel vervolgens Toast.makeText().show()laatste oproep Looper.loop()zoals:

Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()

Antwoord 14

Het antwoord van ChicoBird werkte voor mij. De enige wijziging die ik heb aangebracht was in de creatie van de UIHandler waar ik moest doen

HandlerThread uiThread = new HandlerThread("UIHandler");

Eclipse weigerde iets anders te accepteren. Logisch denk ik.

Ook de uiHandleris duidelijk een globale klasse die ergens is gedefinieerd. Ik beweer nog steeds niet te begrijpen hoe Android dit doet en wat er aan de hand is, maar ik ben blij dat het werkt. Nu ga ik het bestuderen en kijken of ik kan begrijpen wat Android doet en waarom je door al deze hoepels en lussen moet gaan. Bedankt voor de hulp ChicoBird.


Antwoord 15

Voor Rxjava- en RxAndroid-gebruiker:

public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}

Antwoord 16

Ik liep tegen hetzelfde probleem aan toen mijn callbacks probeerden een dialoogvenster weer te geven.

Ik heb het opgelost met speciale methoden in de activiteit – op het activiteitsniveau instancelidmaatschap– die runOnUiThread(..)

gebruiken

public void showAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
        }
    });
}
public void dismissAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
                return;
            }
            mAuthProgressDialog.dismiss();
        }
    });
}

Antwoord 17

Handler handler2;  
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());

Handler2 zal nu een andere thread gebruiken om de berichten te verwerken dan de hoofdthread.


Antwoord 18

Coroutine zal het perfect doen

CoroutineScope(Job() + Dispatchers.Main).launch {
                        Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}

Antwoord 19

Om een dialoog of een broodrooster in een thread weer te geven, is de meest beknopte manier om het Activity-object te gebruiken.

Bijvoorbeeld:

new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...

Antwoord 20

Lambda gebruiken:

activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());

21

Dit gebeurt meestal wanneer iets op de hoofddraad wordt genoemd vanaf elke achtergronddraad. Laten we bijvoorbeeld naar een voorbeeld kijken.

private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

In het bovenstaande voorbeeld stellen we tekst in op het tekstview dat zich in de hoofd-ui-thread van DoInbackground () -methode bevindt, die alleen op een werkdraad werkt.


22

Ik had hetzelfde probleem en ik heb het gewoon opgelost door de toast in onpostexecute () opheft-functie van het Assynctask & LT; & GT; en het werkte.


23

U moet toast maken op UI-draad. Zoek het onderstaande voorbeeld.

runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
  }
});

Voor het weergeven van het Toast-bericht verwijzen wij u naar dit artikel


Antwoord 24

Hier is de oplossing voor Kotlin die Coroutine gebruikt:

Breid uw klas uit met CoroutineScope van MainScope():

class BootstrapActivity :  CoroutineScope by MainScope() {}

Doe dan gewoon dit:

launch {
        // whatever you want to do in the main thread
    }

Vergeet niet de afhankelijkheden voor coroutine toe te voegen:

org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}

Antwoord 25

Java 8

new Handler(Looper.getMainLooper()).post(() -> {
    // Work in the UI thread
}; 

Kotlin

Handler(Looper.getMainLooper()).post{
    // Work in the UI thread
}

GL


Antwoord 26

Handler maken buiten de discussielijn

final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
            try{
                 handler.post(new Runnable() {
                        @Override
                        public void run() {
                            showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
                        }
                    });
                }
            }
            catch (Exception e){
                Log.d("ProvidersNullExp", e.getMessage());
            }
        }
    }).start();

27

Ik heb hetzelfde probleem en dit is wat nu goed met mij werkt
Als voorbeeld is dit mijn code om een ​​taak op de achtergrond en de UI-draad uit te voeren
en kijk naar de looper hoe wordt gebruikt

new Thread(new Runnable() {
              @Override
              public void run() {
              Looper.prepare();
                                // your Background Task here
                runOnUiThread(new Runnable() {
                  @Override
                  public void run() {
                                // update your UI here      
                  Looper.loop();
                                  }
                });
              }
            }).start();

Ik hoop dat dit u of iemand anders helpt


28

Onlangs, ik ontmoet dit probleem – het gebeurde omdat ik probeerde een functie te bellen die een aantal UI-dingen uit de constructor zou doen. Het verwijderen van de initialisatie van de constructeur loste het probleem voor mij op.


29

Ik gebruik de volgende code om een ​​bericht weer te geven van niet-hoofddraad “context”,

@FunctionalInterface
public interface IShowMessage {
    Context getContext();
    default void showMessage(String message) {
        final Thread mThread = new Thread() {
            @Override
            public void run() {
                try {
                    Looper.prepare();
                    Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
                    Looper.loop();
                } catch (Exception error) {
                    error.printStackTrace();
                    Log.e("IShowMessage", error.getMessage());
                }
            }
        };
        mThread.start();
    }
}

gebruik dan als volgt:

class myClass implements IShowMessage{
  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}

Other episodes