是Android新手并尝试重复调用invalidate函数。所以我选择线程来做到这一点。我的线程正常运行但是当试图调用invalidate()时它崩溃下面是代码片段。
class MyCanvas extends View {
private static final String TAG = "MY CANVAS EXAMPLE";
public MyCanvas(Context context){
super(context);
Log.e ( TAG, " MY CANVAS CONSTRUCTOR GOT CALLED ");
// TODO Auto-generated constructor stub
Thread newBackground = new Thread ( new Runnable(){
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
invalidate();
Log.e ( TAG, " MY THREAD GOT CALLED ");
// TODO Auto-generated method stub
}
});
newBackground.start();
}
@Override
protected void onDraw(Canvas canvas) {
Log.e ( TAG, " MY CANVAS GOT CALLED ");
// TODO Auto-generated method stub
super.onDraw(canvas);
}
}
及以下是观察到的崩溃日志
09-23 17:41:09.299: E/MY CANVAS EXAMPLE(1839): MY CANVAS CONSTRUCTOR GOT CALLED
09-23 17:41:09.599: E/MY CANVAS EXAMPLE(1839): MY CANVAS GOT CALLED
09-23 17:41:10.329: W/dalvikvm(1839): threadid=9: thread exiting with uncaught exception (group=0x40018578)
09-23 17:41:10.329: E/AndroidRuntime(1839): FATAL EXCEPTION: Thread-10
09-23 17:41:10.329: E/AndroidRuntime(1839): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
09-23 17:41:10.329: E/AndroidRuntime(1839): at android.view.ViewRoot.checkThread(ViewRoot.java:3020)
09-23 17:41:10.329: E/AndroidRuntime(1839): at android.view.ViewRoot.invalidateChild(ViewRoot.java:647)
09-23 17:41:10.329: E/AndroidRuntime(1839): at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:673)
09-23 17:41:10.329: E/AndroidRuntime(1839): at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
09-23 17:41:10.329: E/AndroidRuntime(1839): at android.view.View.invalidate(View.java:5279)
09-23 17:41:10.329: E/AndroidRuntime(1839): at com.example.canvas.MainActivity$MyCanvas$1.run(MainActivity.java:83)
09-23 17:41:10.329: E/AndroidRuntime(1839): at java.lang.Thread.run(Thread.java:1019)
答案 0 :(得分:1)
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
invalidate()
只能在主UI线程上调用。
请勿使用线程进行此类延迟。相反,请考虑使用Handler
和postDelayed()
发布Runnable
以在延迟后在主UI线程上运行。
(如果您坚持使用单独的线程,如果您想要从后台线程发布postInvalidate()
消息,还有invalidate()
。不使用单独的线程是更好的选择。)
答案 1 :(得分:0)
据我所知,方法invalidate()
不允许在主(UI)线程之外运行。如果您阅读了您所拥有的例外情况,那么您可以看到:
09-23 17:41:10.329: E/AndroidRuntime(1839): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
要解决此问题,只需使用invalidate()
方法在主线程上运行runOnUiThread()
即可。 This question应该为您提供更多信息。
编辑: 更优雅的解决方案是按照BlackBelt的说明调用postInvalidate()
。这样您就不必创建新的Runnable
实例。我有所纠正。
答案 2 :(得分:0)
invalidate();
计划重新设计视图层次结构,而视图层次结构只能由UI线程访问,而不能从后台线程访问。您应该使用postInvalidate()
。从文档
导致后续发生指定区域无效 循环通过事件循环。使用此选项可以使视图无效 非UI线程。