2016-10-13 6 views
3

Почему этот код работает?Почему обработчик, установивший петлитель HandlerThread, может взаимодействовать с объектами пользовательского интерфейса?

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    Log.i("onCreate", Thread.currentThread().toString()); 
    textView = (TextView) findViewById(R.id.textView); 
    imageView = (ImageView) findViewById(R.id.imageView); 

    HandlerThread thread = new HandlerThread("myHandlerThread"); 
    thread.start(); 
    mUiHandler = new Handler(thread.getLooper()); 
    mUiHandler.post(new Runnable() { 
     @Override 
     public void run() { 
      Log.i("Thread: ", Thread.currentThread().toString()); 
      Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show(); 
      textView.setText("Hello Cats"); 
      imageView.setImageResource(R.mipmap.ic_launcher); 
     } 
    }); 

} 

я прочитал где-то, что только поток, который может взаимодействовать с объектами пользовательского интерфейса является потоком пользовательского интерфейса, или я что-то пропустил

у меня есть некоторые исследования, но не нашел ответ еще, пожалуйста, помогите, спасибо много парней.

это то, что я получил от журнала

10-13 18:47:42.888 23841-23841/th.co.me.sampleapp I/onCreate: Thread[main,5,main] 10-13 18:47:42.891 23841-24041/th.co.me.sampleapp I/Thread:: Thread[myHandlerThread,5,main]

UPDATE 1

я попробовал этот код из @nshmura и ошибка происходит это так запутано мне теперь

textView.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     HandlerThread thread = new HandlerThread("myHandlerThread"); 
     thread.start(); 
     mUiHandler = new Handler(thread.getLooper()); 
     mUiHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       Log.i("Thread: ", Thread.currentThread().toString()); 
       Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show(); 
       textView.setText("Hello Cats"); 
       imageView.setImageResource(R.mipmap.ic_launcher); 
      } 
     }); 

    } 
}); 

android.view.ViewRootImpl $ CalledFromWr ongThreadException: Только исходный поток, создавший иерархию представлений, может коснуться его представлений.

+0

я не получаю ваш Que. –

+0

Инициализируйте обработчик с помощью конструктора no-args или с помощью Handler (Looper.getMainLooper()) ... Таким образом, ваш обработчик будет запускаться в основном потоке, и вы можете обновить свои представления из него. –

ответ

-2

Попробуйте этот код

mHandler = new Handler(); 

new Thread(new Runnable() { 
    @Override 
    public void run() { 
     // Perform long-running task here 
     // (like audio buffering). 
     // you may want to update some progress 
     // bar every second, so use handler: 
     mHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       // make operation on UI - on example 
       // on progress bar. 
      } 
     }); 
    } 
}).start(); 
-1

Проверьте, как это:

textView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      HandlerThread thread = new HandlerThread("myHandlerThread"); 
      thread.start(); 
      mUiHandler = new Handler(thread.getLooper()); 
      mUiHandler.post(new Runnable() { 
       @Override 
       public void run() { 
        Log.i("Thread: ", Thread.currentThread().toString()); 
        Toast.makeText(getApplicationContext(), "Hello Cats!", Toast.LENGTH_SHORT).show(); 
        textView.setText("Hello Cats"); 
        imageView.setImageResource(R.mipmap.ic_launcher); 
       } 
      }); 

     } 
    }); 

Исключение будет:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556) 
     at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942) 
     at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081) 
     at android.view.View.invalidateInternal(View.java:12719) 
     at android.view.View.invalidate(View.java:12683) 
     at android.view.View.invalidate(View.java:12667) 
     at android.widget.TextView.checkForRelayout(TextView.java:7156) 
     at android.widget.TextView.setText(TextView.java:4347) 
     at android.widget.TextView.setText(TextView.java:4204) 
     at android.widget.TextView.setText(TextView.java:4179) 

Может быть ViewRootImpl.checkThread() не называется в Activity.onCreate()

+0

Я пробовал этот код и получил такая же ошибка, так запутанная сейчас – kittenforcode

0

исключение android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. будет сгенерировано только если:

  1. вызывается из не Ui нити
  2. вызов требует изменения макета. Например, если размер (ширина и высота) в TextView должен быть продлен из-за слишком длинной строки

Так что, если ваша операция щ не приводит к изменению макета (создать или воссоздать), исключение не могут быть выброшены.

+0

Я запускаю тот же пример, что и OP, с TextView, установленным на 'wrap_content' для ширины и высоты. В примере изменяется текст, не следует ли в тоже время запросить изменение макета? –

+0

да попробуйте его с фиксированным размером – dit

+0

Я думаю, вы пропустили мою мысль ... Я сделал размер 'wrap_content', чтобы вызвать изменение макета. Если вы предложили ответ правильно, приложение выйдет из строя из-за 'CalledFromWrongThreadException', но это не так. –

0

Объект Handler регистрируется в потоке, в котором он создан. Он предоставляет канал для передачи данных в этот поток. Например, если вы создаете новый экземпляр Handler в методе onCreate() вашей активности, его можно использовать для публикации данных в основной поток. Данные, которые могут быть отправлены через класс Handler, могут быть экземпляром класса Message или Runnable.

Таким образом, в соответствии с приведенной ниже строкой ваш обработчик должен принадлежать HandlerThread.

mUiHandler = new Handler(thread.getLooper()); 

Одна вещь, которую я понимаю. OnCreate() является основной нитью, но OnClick Listener - это отдельный класс. Это означает, что есть разница в контексте.

, например:

// onCreate() we are writing like this 
Toast.makeText(this, "Hello Cats!", Toast.LENGTH_SHORT).show(); 
// but in Onclick method we are writing like this 
Toast.makeText(MainActivity.this, "Hello Cats!", Toast.LENGTH_SHORT).show(); 
+0

, если бы это было правдой, почему ошибка все же возникает при использовании кода on метода onClick – kittenforcode

+0

Я переместил созданный экземпляр HandlerThread и Часть обработчика в метод onClick, но ошибка все еще встречается :( – kittenforcode

+0

btw if onClick запускается в другом thead, как он может касаться представлений пользовательского интерфейса – kittenforcode