2013-06-29 3 views
74

Ich habe eine Android App, die einen Thread ausführt. Ich möchte eine Toast-Nachricht mit einer Nachricht anzeigen.java.lang.RuntimeException: Kann einen Handler innerhalb des Threads, der Looper.prepare() nicht aufgerufen hat, nicht erstellen;

Wenn ich das tue, erhalte ich die folgende Ausnahme:

Logcat Spur:

FATAL EXCEPTION: Timer-0 
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$TN.<init>(Toast.java:322) 
at android.widget.Toast.<init>(Toast.java:91) 
at android.widget.Toast.makeText(Toast.java:238) 

Gibt es eine Arbeit um rempelt Toast Nachrichten von Threads auf die Benutzeroberfläche?

+0

http: // stackoverflow.com/questions/4208730/how-to-detect-Benutzer-Inaktivität-in-Android – Amar

+0

Und bei öffentlichen öffentlichen void inactivitydetected() Ich verwendete Toast-Funktion – Amar

Antwort

6

Von http://developer.android.com/guide/components/processes-and-threads.html:

Zusätzlich wird der Android UI-Toolkit nicht Thread-sicher. So, Sie dürfen nicht Ihre Benutzeroberfläche von einem Arbeitsthread manipulieren - Sie müssen alle Manipulation auf Ihrer Benutzeroberfläche aus dem UI-Thread tun. So gibt es einfach zwei Regeln zu Androids einzigen Thread-Modell:

  1. Sie den UI-Thread
  2. nicht blockieren nicht die Android UI-Toolkit

Sie von außerhalb des UI-Thread Zugriff auf Sie muss in einem Worker-Thread Leerlauf erkennen und einen Toast im Hauptthread anzeigen.

Bitte schreiben Sie etwas Code, wenn Sie eine detailliertere Antwort wünschen.

Nach Code Veröffentlichung:

In strings.xml

<string name="idleness_toast">"You are getting late do it fast"</string> 

In YourWorkerThread.java

Toast.makeText(getApplicationContext(), getString(R.string.idleness_toast), 
    Toast.LENGTH_LONG).show(); 

Sie nicht verwenden Alertdialog, eine Wahl treffen. AlertDialog und Toast sind zwei verschiedene Dinge.

+0

idleTimer = neue IdleTimer (5000, neue IdleCallback() @Override öffentlichen Leere inactivityDetected() { \t AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder ( \t \t \t \t getApplicationContext()); \t \t \t \t \t Toast.makeText (null, „Sie bekommen es schnell zu spät zu tun .. . ", Toast.LENGTH_LONG) .show() ; \t } }); \t \t if (idleTimer.checkIsTimerRunning()) { \t \t \t \t idleTimer.stopIdleTimer(); \t \t \t} idleTimer.startIdleTimer(); – Amar

+0

Ich möchte nur, dass die Sache, die ich möchte in meinem IdleTimer-Thread über meine Haupt-ui anzeigen sollte über die ... – Amar

+0

Ich bearbeite meine Antwort, überprüfen Sie es. – baptisterobert

100

Ich habe diese Ausnahme, weil ich versucht habe, ein Toast-Popup aus einem Hintergrund-Thread zu machen.
Toast benötigt eine Aktivität, um zur Benutzeroberfläche zu gelangen, und Threads haben dies nicht.
Eine Problemumgehung besteht also darin, dem Thread eine Verknüpfung zu der übergeordneten Aktivität und Toast zu geben.

Dieser Code in dem Thread, in dem Sie eine Toast Nachricht senden mögen:

parent.runOnUiThread(new Runnable() { 
    public void run() { 
     Toast.makeText(parent.getBaseContext(), "Hello", Toast.LENGTH_LONG).show(); 
    } 
}); 

einen Link zu der übergeordneten Aktivität hält im Hintergrund-Thread, das diesen Thread erstellt.Verwenden Sie übergeordnete Variable in der Thread-Klasse:

private static YourActivity parent; 

Wenn Sie den Thread erstellen, die übergeordnete Aktivität als Parameter durch den Konstruktor wie folgt passieren:

public YourBackgroundThread(YourActivity parent) { 
    this.parent = parent; 
} 

Jetzt ist der Hintergrund-Thread kann Push-Toast-Nachrichten der Bildschirm.

+2

Wie rufe ich eine Methode in dieser Aktivität auf, mit der ich eine Toast-Nachricht mit diesem Code mache? – lxknvlk

+0

Bitte keine weiteren Fragen als Kommentare posten. Kommentare dienen dazu, über die Frage an der Spitze zu sprechen und wie gut meine Antwort darauf antwortet. Es ist wichtig, dass wir die Regeln befolgen. Jeder, der die Regeln befolgt, hält den Stackoverflow großartig und verhindert, dass er zu einem Zirkus wird, wie Yahoo Antworten. –

+0

Erstaunlich !!! Nur die einfache Antwort, die ich brauchte! –

6

Hier ist, was ich getan habe:

public void displayError(final String errorText) { 
    Runnable doDisplayError = new Runnable() { 
     public void run() { 
      Toast.makeText(getApplicationContext(), errorText, Toast.LENGTH_LONG).show(); 
     } 
    }; 
    messageHandler.post(doDisplayError); 
} 

, dass das Verfahren entweder Thread werden genannt ermöglichen soll.

Wo message in der Tätigkeit als deklariert ist ..

Handler messageHandler = new Handler(); 
26

Android funktioniert im Prinzip auf zwei Gewindetypen nämlich UI-Thread und Hintergrund-Thread. Laut Android-Dokumentation -

Zugriff auf das Android-UI-Toolkit von außerhalb des UI-Threads, um dieses Problem zu beheben, bietet Android mehrere Möglichkeiten zum Zugriff auf den UI-Thread von anderen Threads. Hier ist eine Liste von Methoden, die helfen können:

Jetzt gibt es verschiedene Methoden, um dieses Problem zu lösen. Ich werde sie durch Codebeispiel erklären

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 verwendet, um eine Nachrichtenschleife für einen Thread auszuführen. Threads sind standardmäßig nicht mit einer Nachrichtenschleife verknüpft. Um einen zu erstellen, rufen Sie prepare() in dem Thread auf, der die Schleife ausführen soll, und dann loop(), um Nachrichten verarbeiten zu lassen, bis die Schleife gestoppt wird.

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 ermöglicht asynchrone Arbeiten an der Benutzeroberfläche auszuführen. Er führt die Blockierungsvorgänge in einem Worker-Thread aus und veröffentlicht die Ergebnisse dann im UI-Thread, ohne dass Sie Threads und/oder Handler selbst behandeln müssen.

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 
    } 
} 

Handler

Ein Handler ermöglicht es Ihnen, und Nachrichten- und Runnable Objekte Prozess senden mit einem Thread des Message verbunden.

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

Sie können einfach BeginInvokeOnMainThread() verwenden. Es ruft eine Aktion auf dem Gerätehauptthread (UI) auf.

Device.BeginInvokeOnMainThread(() => { displayToast("text to display"); }); 

Es ist einfach und funktioniert perfekt für mich!

BEARBEITEN: Funktioniert, wenn Sie C# Xamarin verwenden

+0

Ist das nicht eine Xamarin-spezifische API und bezieht sich nicht auf diese Frage zu Android Native (ohne Xamarin-Tags)? – Splaktar

+0

Ja, du hast Recht. Entschuldigung dafür, habe ich nicht bemerkt. Aber Leute, die Xamarin verwenden, um nach einer Lösung für den Fehler zu suchen, landen auf dieser Seite. Also habe ich die Post hier gelassen, nur genau, dass es für Xamarin ist. – Vozek

+0

Von welchem ​​Assembly/Namespace kommt 'Device'? – MJ33

Verwandte Themen