View刷新


在Android的布局体系中,父View负责刷新、布局显示子View;而当子View需要刷新时,则是通知父View来完成。
postinvaliate()可以在分线程刷新
invaliate()只能在主线程中执行
横竖屏切换的时候一定会刷新View

1.不使用多线程和双缓冲

     这种情况最简单了,一般只是希望在View发生改变时对UI进行重绘。你只需在Activity中显式地调用View对象中的invalidate()方法即可。系统会自动调用 View的onDraw()方法。

/**
 * Invalidate the whole view. If the view is visible,
 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in
 * the future.
 * <p>
 * This must be called from a UI thread. To call from a non-UI thread, call
 * {@link #postInvalidate()}.
 */
public void invalidate() {
    invalidate(true);
}

@Override
protected void onDraw(Canvas canvas) {
    if (canvas instanceof HardwareCanvas) {
        HardwareCanvas hwCanvas = (HardwareCanvas) canvas;
        mView.mRecreateDisplayList = true;
        RenderNode renderNode = mView.getDisplayList();
        if (renderNode.isValid()) {
            hwCanvas.insertReorderBarrier(); // enable shadow for this rendernode
            hwCanvas.drawRenderNode(renderNode);
            hwCanvas.insertInorderBarrier(); // re-disable reordering/shadows
        }
    }
}

2.使用多线程和不使用双缓冲

     这种情况需要开启新的线程,新开的线程就不好访问View对象了。强行访问的话会报:android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.

     这时候你需要创建一个继承了android.os.Handler的子类,并重写handleMessage(Message msg)方法。android.os.Handler是能发送和处理消息的,你需要在Activity中发出更新UI的消息,然后再你的Handler(可以使用匿名内部类)中处理消息(因为匿名内部类可以访问父类变量, 你可以直接调用View对象中的invalidate()方法 )。也就是说:在新线程创建并发送一个Message,然后再主线程中捕获、处理该消息。

/**
 * 要在Activity中开启一个用于更新的线程
 * timeViewHandler 继承自Handler,用于处理和发送消息
 * MSG_UPDATE 是自定义的一个int常量,用于区分消息类型,可自由取值。
 */
new Thread(new Runnable() {
    @Override
    public void run() {
        while(true){
            try {
                timeViewHandler.sendMessage(Message.obtain(timeViewHandler, MSG_UPDATE));
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}).start();
/**
 * Handler示例,用于刷新时间
 */
public class TimeViewHandler extends Handler {
    private TextView timeView;

    public TextView getTimeView() {
        return timeView;
    }

    public void setTimeView(TextView timeView) {
        this.timeView = timeView;
    }

    public TimeViewHandler(TextView timeView) {
        super();
        this.timeView = timeView;
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE:
                timeView.setText(DateHelper.getNow("kk:mm:ss"));
                timeView.invalidate();
                break;
        }
        super.handleMessage(msg);
    }

}
3.使用多线程和双缓冲

    Android中SurfaceView是View的子类,她同时也实现了双缓冲。也可以定义一个她的子类并实现SurfaceHolder.Callback接口。由于实现SurfaceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。SurfaceHolder中lockCanvas()方法可以锁定画布,绘制玩新的图像后调用unlockCanvasAndPost(canvas)解锁(显示),还是比较方便得。

/**
 * SurfaceView使用示例,TouchDrawView主要完成屏幕的指尖绘画
 */
public class TouchDrawView extends SurfaceView implements SurfaceHolder.Callback{
    private SurfaceHolder holder;
    private TouchDrawListener listener;

    public TouchDrawListener getListener() {
        return listener;
    }

    public void setListener(TouchDrawListener listener) {
        this.listener = listener;
    }

    public TouchDrawView(Context context) {
        super(context);
        holder = getHolder();
        holder.addCallback(this);
        listener = new TouchDrawListener(holder);
        listener.setShape(TouchDrawListener.SHAPE_LINE);
        listener.setShape_style(TouchDrawListener.SHAPE_STYLE_FILL);
        this.setOnTouchListener(listener);//设置屏幕事件监听器
        this.setLongClickable(true);//不设置将无法捕捉onFling()事件
        setFocusable(true);//设置键盘焦点
        setFocusableInTouchMode(true);//设置触摸屏焦点
    }

    public TouchDrawView(Context context, AttributeSet as) {
        this(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        //关键部分
        Canvas canvas = holder.lockCanvas(null);//获取画布  
        canvas.drawColor(Color.WHITE);//白色背景
        holder.unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像  
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

    }
}
使用postInvalidate()刷新界面
   使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。
class GameThread implements Runnable {
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            // 使用postInvalidate可以直接在线程中更新界面
            mGameView.postInvalidate();
        }
    }
}
 
  
 
  

你可能感兴趣的:(view刷新)