
[英]Why is this Runnable ran on the main thread after the being posted by a Handler constructed with a Looper from a HandlerThread?
[英]Why does Handler that have set a looper of HandlerThread can interact with UI Objects?
为什么此代码有效?
@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);
}
});
}
我从某处读取到可以与UI对象通信的唯一线程是UI线程,或者我错过了一些东西
我有一些研究,但尚未找到答案,请帮助,非常感谢你们。
这是我从日志中得到的
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:只有创建视图层次结构的原始线程才能触摸其视图。
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
异常android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
仅在以下情况下将被抛出:
TextView
的大小(宽度和高度) 因此,如果您的ui操作不会导致布局更改(创建或重新创建),则可能不会引发异常。
Handler对象向创建它的线程注册自己。 它提供了一个向该线程发送数据的通道。 例如,如果您在活动的onCreate()方法中创建一个新的Handler实例,则可以使用该实例将数据发布到主线程。 可以通过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)
也许未在Activity.onCreate()
调用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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.