Android中AsyncTask调用invalidate()无法刷新视图,求助
解决自定义视图调用invalidate后不刷新的问题
嘿,我来帮你排查这个视图不刷新的问题!先直接说几个关键问题和修复方案:
1. 最核心的错误:AsyncTask启动方式不对
你直接调用了movieTask.doInBackground(null),这完全违背了AsyncTask的设计!doInBackground是AsyncTask内部在后台线程执行的方法,必须通过调用execute()来启动任务,否则:
- 任务会在UI线程直接运行,导致界面卡顿甚至ANR
publishProgress无法正确触发onProgressUpdate回调(因为AsyncTask的生命周期没被正确初始化)
修复后的startMovie方法:
public void startMovie(){ MovieTask movieTask = new MovieTask(myView, this); movieTask.execute(); // 用execute()启动,而不是直接调用doInBackground }
2. 多余的UI线程嵌套
AsyncTask的onProgressUpdate方法本身就是运行在UI线程的,你不需要再嵌套mainActivity.runOnUiThread,虽然这不会直接导致刷新失败,但属于冗余代码,去掉更简洁:
修改后的MovieTask的onProgressUpdate:
@Override protected void onProgressUpdate(String... values) { super.onProgressUpdate(values); Log.v("DEBUG_DRAW","in onProgressUpdate()"); drawingView.invalidate(); }
3. 必须确保MyView的onDraw读取最新数据
你调用了invalidate()但视图没刷新,很大概率是MyView的onDraw方法没有使用myBall的最新坐标。检查你的MyView的onDraw实现,确保它每次绘制都读取myBall的当前位置,比如:
public class MyView extends View { public Ball myBall; private Paint paint; private int radius = 50; public MyView(Context context) { super(context); paint = new Paint(); paint.setColor(Color.RED); myBall = new Ball(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 每次绘制都获取myBall的最新坐标 canvas.drawCircle(myBall.getX(), myBall.getY(), radius, paint); } }
4. 线程可见性问题(容易忽略)
因为doInBackground在后台线程修改myBall的坐标,而onDraw在UI线程读取,可能会出现线程可见性问题(后台线程修改的值UI线程看不到)。给Ball类的坐标字段加上volatile修饰,确保修改能立即被其他线程看到:
public class Ball { // 用volatile保证线程可见性 private volatile int x; private volatile int y; public void goTo(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } }
按照上面的步骤修改后,你的视图应该就能正常刷新了!另外提一句:AsyncTask在Android API 30之后已经被标记为过时了,新项目推荐用Coroutines或者ExecutorService+Handler来实现后台任务,但先解决当前问题为主~
内容的提问来源于stack exchange,提问作者mcfly soft
相关产品推荐
相关产品推荐

