Android如何解决从错误线程触摸View的问题?

发布于 2024-09-28 21:56:43 字数 2671 浏览 2 评论 0原文

我收到错误“CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。”

问题来自TutorialThread 中的onDraw 调用。如果调用该代码,则该代码有效 onDraw 中的 startAnimation 被删除。为什么删除 startAnimation 后代码还能工作? 为什么此调用与对drawRect的调用不同?

下面是代码:

public class GamePanel extends Activity { 私人面板 mPanel;

public void onCreate(Bundle savedInstanceState) {       
    super.onCreate(savedInstanceState);
    mPanel = new Panel(this);
    setContentView(mPanel);
    mPanel.requestFocus(); 
}

}

类Panel 扩展SurfaceView 实现SurfaceHolder.Callback{ 私人教程线程_线程; 私人画图mPaint; 上下文上下文; 私人最终 GamePanel 游戏;

public Panel(Context context) {
    super(context); 
    this.game = (GamePanel) context;
    getHolder().addCallback(this);
    _thread = new TutorialThread(getHolder(),this);

    setFocusable(true);
    mPaint = new Paint();
}  
@Override
public void onDraw(Canvas canvas) {             
    canvas.drawARGB(255, 0, 0, 0);              
    mPaint.setColor(Color.WHITE);
    mPaint.setStyle(Paint.Style.FILL);
    canvas.drawRect(100, 100, 150, 150, mPaint);
    startAnimation(AnimationUtils.loadAnimation(game,R.anim.shake));
}               
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){

}
@Override
public void surfaceCreated(SurfaceHolder holder){
    _thread.setRunning(true);
    _thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
    boolean retry = true;
    _thread.setRunning(false);
    while(retry) {
        try {
            _thread.join();
            retry = false;
        } catch(InterruptedException e) {

        }
    }
}

class TutorialThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;

    public TutorialThread(SurfaceHolder surfaceHolder,Panel panel){
        _surfaceHolder = surfaceHolder;
        _panel = panel;
    }
    public void setRunning(boolean run){
        _run = run;
    }
    @Override
    public void run(){
        Canvas c;
        while(_run){
            c=null;
            try{
                c = _surfaceHolder.lockCanvas(null);
                synchronized(_surfaceHolder){                       
                    _panel.onDraw(c);
                }
            }finally{
                if(c!=null){
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
            try
            {
                Thread.sleep(500);
            }
                catch(InterruptedException Ie) {
            }                   
        }           
    }       
}

}

I get the fault "CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."

The problem commes from the onDraw call in TutorialThread. The code works if the call to
startAnimation in onDraw is removed. Why does the code work if startAnimation is removed?
Why is this call different than the call to drawRect?

Below is the code:

public class GamePanel extends Activity {
private Panel mPanel;

public void onCreate(Bundle savedInstanceState) {       
    super.onCreate(savedInstanceState);
    mPanel = new Panel(this);
    setContentView(mPanel);
    mPanel.requestFocus(); 
}

}

class Panel extends SurfaceView implements SurfaceHolder.Callback{
private TutorialThread _thread;
private Paint mPaint;
Context context;
private final GamePanel game;

public Panel(Context context) {
    super(context); 
    this.game = (GamePanel) context;
    getHolder().addCallback(this);
    _thread = new TutorialThread(getHolder(),this);

    setFocusable(true);
    mPaint = new Paint();
}  
@Override
public void onDraw(Canvas canvas) {             
    canvas.drawARGB(255, 0, 0, 0);              
    mPaint.setColor(Color.WHITE);
    mPaint.setStyle(Paint.Style.FILL);
    canvas.drawRect(100, 100, 150, 150, mPaint);
    startAnimation(AnimationUtils.loadAnimation(game,R.anim.shake));
}               
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){

}
@Override
public void surfaceCreated(SurfaceHolder holder){
    _thread.setRunning(true);
    _thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder){
    boolean retry = true;
    _thread.setRunning(false);
    while(retry) {
        try {
            _thread.join();
            retry = false;
        } catch(InterruptedException e) {

        }
    }
}

class TutorialThread extends Thread {
    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;

    public TutorialThread(SurfaceHolder surfaceHolder,Panel panel){
        _surfaceHolder = surfaceHolder;
        _panel = panel;
    }
    public void setRunning(boolean run){
        _run = run;
    }
    @Override
    public void run(){
        Canvas c;
        while(_run){
            c=null;
            try{
                c = _surfaceHolder.lockCanvas(null);
                synchronized(_surfaceHolder){                       
                    _panel.onDraw(c);
                }
            }finally{
                if(c!=null){
                    _surfaceHolder.unlockCanvasAndPost(c);
                }
            }
            try
            {
                Thread.sleep(500);
            }
                catch(InterruptedException Ie) {
            }                   
        }           
    }       
}

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一曲琵琶半遮面シ 2024-10-05 21:56:43

您应该使用 AsyncTask,而不是自定义 Thread 类。 AsyncTask 可以正确且轻松地使用 UI 线程。

Instead of your custom Thread class you should use AsyncTask. AsyncTask enables proper and easy use of the UI thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文