当前位置:操作系统 > 安卓/Android >>

Android View 绘制刷新流程分析

Android中对View的更新有很多种方式,使用时要区分不同的应用场合。
1.不使用多线程和双缓冲
     这种情况最简单,一般只是希望在View发生改变时对UI进行重绘。你只需显式地调用View对象中的invalidate(){关于invalidate的解释:当调用线程处于空闲状态时,会调用onDraw,刷新界面,也就是说,该函数仅是标记当前界面过期,并不直接负责刷新界面;}方法即可。系统会自动调用View的onDraw()方法。
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,然后再主线程中捕获、处理该消息。
3.使用多线程和双缓冲
    Android中Su易做图ceView是View的子类,她同时也实现了双缓冲。可以定义一个她的子类并实现Su易做图ceHolder.Callback接口。由于实现Su易做图ceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。Su易做图ceHolder中lockCanvas()方法可以锁定画布,绘制完新的图像后调用unlockCanvasAndPost(canvas)解锁(显示)
先看看源代码对Su易做图ceHolder接口的描述


/**
 * 允许你控制su易做图ce view的大小、样式,编辑像素或监视su易做图ce的改变,典型的运用于Su易做图ceView中,需要注意 * lockCanvas方法和Callback.su易做图ceCreated方法*/再看Su易做图ceHolder.Callback的描述


    /**
     * A client may implement this inte易做图ce to receive information about
     * changes to the su易做图ce.  When used with a {@link Su易做图ceView}, the
     * Su易做图ce being held is only available between calls to
     * {@link #su易做图ceCreated(Su易做图ceHolder)} and
     * {@link #su易做图ceDestroyed(Su易做图ceHolder)}.  The Callback is set with
     * {@link Su易做图ceHolder#addCallback Su易做图ceHolder.addCallback} method.
     */下面是一个继承自Su易做图ceView并实现Su易做图ceHolder.Callback接口的类


public class MySu易做图ceView extends Su易做图ceView implements Su易做图ceHolder.Callback {
    private Su易做图ceHolder holder;

    public MySu易做图ceView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MySu易做图ceView(Context context) {
        super(context);
        holder = this.getHolder();
        holder.addCallback(this);
        this.setLongClickable(true);// 不设置将无法捕捉onFling()事件
        setFocusable(true);// 设置键盘焦点
        setFocusableInTouchMode(true);// 设置触摸屏焦点
    }

    protected void paintView(Canvas canvas) { // 自定义方法,类似于onDraw
    }public void rePaint() { // 自定义类似于invalidate方法,调用此方法刷新View
        Canvas c = null;
        try {
            c = holder.lockCanvas();
            paintView(c);
        } finally {
            if (c != null) {
                holder.unlockCanvasAndPost(c);
            }
        }
    }

    @Override
    public void su易做图ceCreated(Su易做图ceHolder holder) {
        Canvas canvas = holder.lockCanvas(null);// 获取画布
        canvas.drawColor(Color.WHITE);// 设置画布背景
        holder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
    }

    @Override
    public void su易做图ceChanged(Su易做图ceHolder holder, int format, int width,
            int height) {
    }

    @Override
    public void su易做图ceDestroyed(Su易做图ceHolder holder) {
    }
}------------------------------------------------------View的绘制流程-----------------------------------------------------

View的绘制绘制流程:父View负责刷新、布局、显示子View;而当子View需要刷新时,则是通知父View来完成。下面通过查看原代码来验证
1.子类调用invalidate方法()


    /**
     * 使当前View无效. 如果View可见,onDraw方法将会在之后某个时间点被调用,这个方法的调用必须在UI线程中,如果在非UI线程中调用需要使用postInvalidate()方法*/
    public void invalidate() {
        invalidate(true);
    }

    /**
     * invalidate实际上是调用这个方法.drawing的缓存被设置为无效之后一个完整的invalidate将会发生.但是这个功能可以通过设置invalidateCachefalse来跳过无效的步骤当并不需要重新绘制View的时候(例如,一个组件保持着同样的尺寸和内容)
     * @param invalidateCache 这个View的缓存是否应该被设置为无效,通常是false表示要进行全部绘制,但是可能设置为true当View的Content和dimension都没有改变时.
     */
    void invalidate(boolean invalidateCache) {
        if (skipInvalidate()) {
            return;
        }
        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
                (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
            // ......final AttachInfo ai = mAttachInfo; // 获取匹配
            final ViewParent p = mParent; // 获取父类对象
            // noinspection PointlessBooleanExpression,ConstantConditions
            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
                if (p != null && ai != null && ai.mHardwareAccelerated) {
                    p.invalidateChild(this, null);
                   

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,