在单独的线程中调用invalidate时崩溃

时间:2014-09-23 12:16:18

标签: android canvas

是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)

3 个答案:

答案 0 :(得分:1)

android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

invalidate()只能在主UI线程上调用。

请勿使用线程进行此类延迟。相反,请考虑使用HandlerpostDelayed()发布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线程。