Почему Handler, который установил петлитель 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]
ОБНОВЛЕНИЕ 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$CalledFromWrongThreadException: только исходный поток, создавший иерархию представлений, может касаться его представлений.
4 ответа
Исключение android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
будет брошено только если:
- вызывается из не пользовательского потока
- вызов требует изменения макета. Например, если размер (ширина и высота)
TextView
должен быть расширен из-за слишком длинной строки
Поэтому, если ваша операция с пользовательским интерфейсом не приводит к изменению макета (созданию или воссозданию), исключение может не возникать.
Объект-обработчик регистрируется в потоке, в котором он создан. Он предоставляет канал для отправки данных в этот поток. Например, если вы создаете новый экземпляр 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();
Проверьте вот так:
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()
Попробуйте этот код
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();