2013-06-29 92 views
74

我有一個運行線程的Android應用程序。我想要一條Toast消息來顯示消息。java.lang.RuntimeException:無法在未調用Looper.prepare()的線程中創建處理程序;

當我這樣做,我得到以下異常:

logcat的跟蹤:

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) 

是否有來自線程推吐司消息到用戶界面的解決辦法?

+0

http:// stackoverflow。COM /問題/ 4208730 /如何對檢測用戶不活動功能於Android的 – Amar

+0

而在inactivitydetected重載公共無效()我用吐司功能 – Amar

回答

6

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

另外,Android的UI工具包不是線程安全的。 所以,你的 不得從工作線程操縱你的UI - 你必須從UI線程對你的用戶界面進行所有的 操作。因此,有 只是兩個規則Android的單線程模型:

  1. 不要阻塞UI線程
  2. 不要從UI線程外部訪問Android的UI工具包

你必須檢測工作線程中的閒置並在主線程中顯示一個敬酒。

請張貼一些代碼,如果你想得到更詳細的答案。

代碼公佈後:

strings.xml

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

YourWorkerThread.java

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

不要使用AlertDialog,做出選擇。 AlertDialog和Toast是兩個不同的東西。

+0

idleTimer =新IdleTimer(5000,新IIdleCallback(){ @覆蓋 公衆無效inactivityDetected(){ \t AlertDialog.Builder alertDialogBu​​ilder =新AlertDialog.Builder( \t \t \t \t getApplicationContext()); \t \t \t \t \t Toast.makeText(NULL,「你越來越晚做快.. 。「,Toast.LENGTH_LONG) .show() ; \t } }); \t \t如果(idleTimer.checkIsTimerRunning()){ \t \t \t \t idleTimer.stopIdleTimer(); \t \t \t} idleTimer.startIdleTimer(); – Amar

+0

我只想讓我的idleTimer線程顯示在我的主UI上顯示出來... – Amar

+0

我編輯我的答案,檢查它。 – baptisterobert

100

我得到這個異常,因爲我試圖從後臺線程做一個Toast彈出。
Toast需要一個活動推送到用戶界面,線程沒有這個。
所以一個解決方法是給線程一個父Activity和Toast的鏈接。

把這個代碼在您要發送一個吐司消息的線程:

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

請創建此線程後臺線程的鏈接父活動。使用父變量在你的線程類:

private static YourActivity parent; 

當您創建線程,通過構造這樣通過父活動作爲參數:

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

現在後臺線程可以把吐司消息屏幕。

+2

如何在該活動中調用一個方法,我使用此代碼製作吐司消息? – lxknvlk

+0

請不要將後續問題作爲評論發佈。評論是爲了討論頂部的問題,以及我的答案如何回答這個問題。遵守規則很重要。遵守這些規則的每個人都是讓stackoverflow變得更好,並且防止它像雅虎的回答一樣變成馬戲團。 –

+0

令人驚歎!只是我需要的簡單答案! –

6

這是我一直在做的事情:

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

這應該允許從任何線程調用的方法。

MessageHandler的地方在活動的聲明..

Handler messageHandler = new Handler(); 
26

Android的基本工作原理上的兩個螺紋類型,即UI線程和後臺線程。根據android文檔 -

不要從UI線程外部訪問Android UI工具包來解決這個問題,Android提供了幾種方法從其他線程訪問UI線程。這裏有一個可以幫助的方法列表:

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

現在有各種方法來解決這個問題。我將代碼示例

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

類解釋它。線程默認沒有與它們相關的消息循環;創建一個,在要運行循環的線程中調用prepare(),然後循環()使其處理消息,直到循環停止。

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允許您在用戶界面上執行異步工作。它在工作線程中執行阻塞操作,然後將結果發佈到UI線程上,而無需您自己處理線程和/或處理程序。

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

處理器

一個處理程序允許您發送和處理消息並Runnable對象與線程的MessageQueue關聯。

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

您可以簡單地使用BeginInvokeOnMainThread()。它在設備主(UI)線程上調用一個Action。

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

它是簡單和完美的作品對我來說!

編輯:如果您使用的是C#Xamarin

+0

這不是一個Xamarin特定的API,並且不涉及有關Android Native(不包含Xamarin標記)的這個問題嗎? – Splaktar

+0

是的,你是對的。對不起,我沒有注意到。 但是,使用Xamarin尋找錯誤解決方案的用戶登陸此頁面。所以我讓這裏的帖子,只是爲Xamarin準備。 – Vozek

+0

'裝置'從哪個裝配/名稱空間來? – MJ33

相關問題