2013-06-29 4 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/questions/4208730/how-to-detect-user-inactivity-in-android – Amar

+0

И при переопределении public void inactivitydetected() Я использовал функцию тоста – Amar

ответ

6

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

Кроме того, инструментарий Android UI не поточно-. Итак, вы не должны манипулировать вашим пользовательским интерфейсом из рабочего потока -You должен сделать все манипуляции с вашим пользовательским интерфейсом из потока пользовательского интерфейса. Таким образом, просто два правила для одной модели потоков Андроида:

  1. Не блокировать поток пользовательского интерфейса
  2. Не доступа инструментарий 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() { @Override public недействительным inactivityDetected() { \t AlertDialog.Builder alertDialogBuilder = новый AlertDialog.Builder ( \t \t \t \t getApplicationContext()); \t \t \t \t \t Toast.makeText (нулевой, «вы поздно сделать это быстро .. . ", 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 требует действия, чтобы нажать на пользовательский интерфейс, и потоки не имеют этого.
Итак, одним из способов является предоставление потоку ссылки на родительскую активность и тосты.

Поместите этот код в потоке, в котором вы хотите отправить сообщение Тост:

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 отличным, и препятствует тому, чтобы он превратился в цирк, похожий на ответы yahoo. –

+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 в основном работает на двух видах резьбы, а именно поток пользовательского интерфейса и фоновый поток. Согласно документации android -

Не обращайтесь к инструментарию Android UI из-за пределов пользовательского интерфейса, чтобы исправить эту проблему, Android предлагает несколько способов доступа к потоку пользовательского интерфейса из других потоков. Вот список методов, которые могут помочь:

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() в потоке, который должен запустить цикл, а затем loop(), чтобы обработать сообщения до тех пор, пока цикл не будет остановлен.

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 позволяет выполнить асинхронную работу на пользовательском интерфейсе. Он выполняет операции блокировки в рабочем потоке, а затем публикует результаты в потоке пользовательского интерфейса, не требуя, чтобы вы сами обрабатывали потоки и/или обработчики.

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

обработчиком позволяет передавать и обрабатывать сообщения и 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).

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

Это просто и прекрасно работает для меня!

EDIT: Работает, если вы используете C# Xamarin

+0

Разве это не специфический API Xamarin и не связанный с этим вопросом об Android Native (без тегов Xamarin)? – Splaktar

+0

Да, вы правы. Извините за это, я не заметил. Но люди, использующие Xamarin для поиска решения ошибки, приземляются на этой странице. Поэтому я отпустил этот пост, просто уточнив его для Xamarin. – Vozek

+0

Из чего происходит сборка/пространство имен «Устройство»? – MJ33