public class ThreadView extends View {
Paint paint = new Paint();
int count;
Handler uiThread = new Handler();
public ThreadView(Context context, AttributeSet attrs) {
super(context, attrs);
paint.setColor(Color.BLACK);
paint.setTextSize(80);
uiThread.post(new Runnable() {
@Override
public void run() {
while(true) {
count++;
invalidate();
}
}
});
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawText(count + "", 100, 100, paint);
}
}
我在自定义视图中看到了这个solution的线程,但它没有用。即使我的循环继续调用invalidate()
,它也不会继续调用onDraw()
我也看到了一个解决方案,他们实现了Runnable和overrode run()
这是一个更好的方法吗?
答案 0 :(得分:4)
所有视图都已经为它们设置了处理程序,因此创建另一个视图效率很低。相反,你应该使用View类' post(Runnable action)或postDelayed(Runnable action,long delayMillis)方法。
就你想要完成的事情而言,我假设你提供的代码只是作为一个例子。如果您真的只是想更新一些文本,我会说使用TextView并在其上调用setText。当TextView知道文本已经改变时,TextView会自行处理。
但回到你的问题。很大程度上取决于您想要更新计数变量的渲染率。您目前将在UI线程上无限循环运行。这肯定会导致问题,因为您将使用无效调用垃圾邮件处理程序/事件队列,同时阻止其他任何内容在UI线程上运行。
相反,我建议引入可配置的定时延迟,以及停止更新视图的方法。
例如,您可以设置为每隔10秒钟使视图无效,并且只有在您的视图附加到窗口时才更新计数器(请注意,Runnable本身负责是否应该运行再次基于updateView标志的值):
public class ThreadView extends View {
private class UpdateViewRunnable implements Runnable {
public void run() {
count++;
invalidate();
if (updateView) {
postDelayed(this, DELAY_TIME_MILLIS);
}
}
}
private static final long DELAY_TIME_MILLIS = 100L;
private boolean updateView = false;
private UpdateViewRunnable updateViewRunnable = new UpdateViewRunnable();
private Paint paint = new Paint();
private int count;
public ThreadView(Context context) {
super(context);
init(context, null);
}
public ThreadView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
paint.setColor(Color.BLACK);
paint.setTextSize(80);
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawText(count + "", 100, 100, paint);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
updateView = true;
postDelayed(updateViewRunnable, DELAY_TIME_MILLIS);
}
@Override
public void onDetachedFromWindow() {
updateView = false;
super.onDetachedFromWindow();
}
}
答案 1 :(得分:0)
首先,在你提供的代码片段中根本不需要处理程序,你可以只使用View.post方法,因为在UI线程中已经调用了构造函数。
其次,invalidate导致ui更新的原因是
1,方法View.invalide将任务放入UI线程的队列中并返回。通常,当UI线程获得其执行的CPU时间份额时,它将按顺序执行这些任务,然后重新绘制视图。
然而,2,你发布的Runnable在UI线程中进行无限循环,并且无效调用创建的重绘任务正在排队,但永远不会被处理,应用程序很可能会冻结。