Why Is There No Calledfromwrongthreadexception When A New Thread Operates Ui Immediately?
Solution 1:
The root cause of the crash is the ViewRootImpl.checkThread ()
method.
voidcheckThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views.");
}
However, the invalidate ()
method is not called when the view is not measured , the invalidate()
method will eventually execute to the checkThread()
.
ok , see :
newThread(newRunnable() {
@Overridepublicvoidrun() {
System.err.println("getMeasuredHeight:" + parentView.getMeasuredHeight());
System.err.println("getMeasuredWidth:" + parentView.getMeasuredWidth());
parentView.removeView(view);
}
}).start();
will get that:
W/System.err: getMeasuredWidth:0W/System.err: getMeasuredHeight:0
can see, the measurement process has not been completed , so we can change the UI without triggering the invalidate()
and not trigger exception.
then, keep it sleep 50 ms:
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("getMeasuredHeight:" + parentView.getMeasuredHeight());
System.err.println("getMeasuredWidth:" + parentView.getMeasuredWidth());
parentView.removeView(view);
}
}).start();
will get that:
W/System.err: getMeasuredHeight:360W/System.err: getMeasuredWidth:1080
can see, the measurement process has been completed, then , when we change the UI the invalidate
will be triggering,and then it call the checkThread()
.
Solution 2:
In short, avoid manipulating Android UI elements off the UI Thread; you're going to run into unpredictable behaviour.
You can synchronize your update to the UI by using Activity.runOnUiThread(Runnable r)
, which should alleviate the problem. i.e.
newThread(newRunnable(){
@Overridepublicvoidrun() {
try{
Thread.sleep(3000);
// Synchronize on the UI Thread.
MainActivity.this.runOnUiThread(newRunnable() { @Overridepublicfinalvoidrun() {
// Remove the View.
parentView.removeView(view);
} });
}
catch (Exception e){
e.printStackTrace();
}
}
}).start();
However, there is a much better construct you should be using; you should never underestimate the computational burden of allocating and running a new Thread
!
You can achieve the exact same functionality using:
(newHandler(Looper.getMainLooper())).postDelayed(newRunnable() {
/* Update the UI. */
}, 3000));
This will achieve the same behaviour, without leaving you having to worry about managing synchronization along the UI Thread. Additionally, you won't be launching a whole new Thread
whose only job is to sleep!
This should perform a great deal better.
Solution 3:
No need to use a thread for a delay, instead :
newThread(newRunnable(){
@Overridepublicvoidrun() {
try{
Thread.sleep(3000);
}catch (Exception e){
}
parentView.removeView(view);
}
}).start();
Do :
newHandler().postDelayed(newRunnable() {
@Overridepublicvoidrun() {
parentView.removeView(view);
}
}, 3000);
Post a Comment for "Why Is There No Calledfromwrongthreadexception When A New Thread Operates Ui Immediately?"