在自定义视图中使用线程

时间:2015-06-10 21:31:05

标签: android multithreading android-custom-view

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()这是一个更好的方法吗?

2 个答案:

答案 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线程中进行无限循环,并且无效调用创建的重绘任务正在排队,但永远不会被处理,应用程序很可能会冻结。