SurfaceView学习中遇到的问题

1. 听说游戏开发都用Surfaceview,上网搜了下,说是SurfaceView在更新视图时,采用了双缓存机制,可以提高更新效率,加强用户体验。下面两段粘贴自别人的博客,说的还挺清楚的。

Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor() or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.

在运用时可以理解为:SurfaceView在更新视图时用到了两张Canvas,一张frontCanvas和一张backCanvas,每次实际显示的是frontCanvas,backCanvas存储的是上一次更改前的视图,当使用lockCanvas()获取画布时,得到的实际上是backCanvas而不是正在显示的frontCanvas,之后你在获取到的backCanvas上绘制新视图,再unlockCanvasAndPost(canvas)此视图,那么上传的这张canvas将替换原来的frontCanvas作为新的frontCanvas,原来的frontCanvas将切换到后台作为backCanvas。例如,如果你已经先后两次绘制了视图A和B,那么你再调用lockCanvas()获取视图,获得的将是A而不是正在显示的B,之后你讲重绘的C视图上传,那么C将取代B作为新的frontCanvas显示在SurfaceView上,原来的B则转换为backCanvas。

2. 在网上依样画葫芦写了短代码,结果send to background的时候会crash。Debug后发现原因是没检查SurfaceHolder获得的Canvas是不是为空。在surfaceDestroyed之后,Canvas肯定没有了,所以要检查。

public class DemoSurfaceView extends SurfaceView implements Callback{

    LoopThread thread;  

    public DemoSurfaceView(Context context) {
        super(context);
        init();
    }  

    private void init(){
        SurfaceHolder holder = getHolder();
        thread = new LoopThread(holder, getContext());
        holder.addCallback(this);
    }  

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        thread.isRunning = true;
        thread.start();
    }  

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.i("Hailin", "surfaceDestroyed");
        thread.isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }  

    class LoopThread extends Thread{  

        SurfaceHolder surfaceHolder;
        Context context;
        boolean isRunning;
        float radius = 10f;
        Paint paint;  

        public LoopThread(SurfaceHolder surfaceHolder,Context context){  

            this.surfaceHolder = surfaceHolder;
            this.context = context;
            isRunning = false;  

            paint = new Paint();
            paint.setColor(Color.YELLOW);
            paint.setStyle(Paint.Style.STROKE);
        }  

        @Override
        public void run() {  

            Canvas c = null;  

            while(isRunning){  

                try{
                    synchronized (surfaceHolder) {  

                        if(surfaceHolder == null) {
                            Log.i("Hailin", "surfaceHolder == null");
                        }

                        c = surfaceHolder.lockCanvas(null);
                        if(c == null) {
                            Log.i("Hailin", "c == null");
                            return;
                        }
                        doDraw(c);
                        Thread.sleep(50);
                        surfaceHolder.unlockCanvasAndPost(c);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {  

                }  

            }  

        }  

        public void doDraw(Canvas c){  

            c.drawColor(Color.BLACK);
            c.translate(200, 200);
            c.drawCircle(0,0, radius++, paint);  

            if(radius > 100){
                radius = 10f;
            }  

        }  

    }
}

3. 照着《疯狂Android讲义》敲了断代码,发现在点击屏幕后在surfaceCreated里面画的背景图老是丢失。如果直接用Surfaceview.setBackground来设置背景,点击屏幕画的图会被背景图非黑色部分给遮住(背景图本来是白色背景,但是画上去都变黑色背景了)。最后只能在onTouch里面重新画一遍背景图。

public class SVTest extends Activity {

    private SurfaceHolder holder;
    private Paint paint;
    private SurfaceView surface;
    private Canvas canvas;
    private boolean isTouched;
    private Bitmap mBitmap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.svtest);

        paint = new Paint();
        surface = (SurfaceView) this.findViewById(R.id.svTest);

        final Bitmap back = BitmapFactory.decodeResource(SVTest.this.getResources(), R.drawable.ic_launcher);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        int mScreenWidth = dm.widthPixels;
        int mScreenHeight = dm.heightPixels;
        mBitmap = Bitmap.createScaledBitmap(back, mScreenWidth, mScreenHeight, true); 

        // actually it set a Drawable with pure color as background
//        surface.setBackgroundColor(Color.WHITE);
        // set background Drawable
//        surface.setBackgroundResource(R.drawable.ic_launcher);

        holder = surface.getHolder();
        holder.addCallback(new Callback() {

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                // TODO Auto-generated method stub
                Log.i("Hailin", "surfaceCreated");

//                set background
                canvas = holder.lockCanvas();
                canvas.drawBitmap(mBitmap, 0, 0, null);
                holder.unlockCanvasAndPost(canvas);
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {
                // TODO Auto-generated method stub
                Log.i("Hailin", "surfaceChanged");
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // TODO Auto-generated method stub
                Log.i("Hailin", "surfaceDestroyed");
            }

        });

        surface.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                if(event.getAction() == MotionEvent.ACTION_DOWN) {
                    if(!isTouched) {
                        // set background again
                        canvas = holder.lockCanvas();
                        canvas.drawBitmap(mBitmap, 0, 0, null);
                        holder.unlockCanvasAndPost(canvas);

                        isTouched = true;
                    }
                    int cx = (int) event.getX();
                    int cy = (int) event.getY();
                    Canvas canvas = holder.lockCanvas(new Rect(cx - 50, cy - 50, cx + 50, cy + 50));
                    canvas.save();
                    canvas.rotate(30, cx, cy);
                    paint.setColor(Color.RED);
                    canvas.drawRect(cx - 50, cy - 50, cx, cy, paint);
                    canvas.restore();
                    paint.setColor(Color.GREEN);
                    canvas.drawRect(cx, cy, cx + 50, cy + 50, paint);
                    holder.unlockCanvasAndPost(canvas);
                }
                return false;
            }

        });
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i("Hailin", "onResume");
    }

    @Override
    public void onPause() {
        super.onPause();
        Log.i("Hailin", "onPause");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("Hailin", "onDestroy");
    }

}

时间: 2024-08-27 09:44:25

SurfaceView学习中遇到的问题的相关文章

Android之SurfaceView学习(一)转转

Android之SurfaceView学习(一) 首先我们先来看下官方API对SurfaceView的介绍 SurfaceView的API介绍 Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of pla

学编程,学单词.....在学习中积累自己的单词(不断更新__ing)

可以去肆意大话天下,可以去小民一般的言语,但是一定要清楚,知识的积累,至于心中,这样,你才能低至市井,上至高阁....畅通无阻! 1.  Loowater  厕所水 , Loo 盥洗室 学编程,学单词.....在学习中积累自己的单词(不断更新__ing),布布扣,bubuko.com

MFC学习中遇到的小问题和解决方案

1 清除combox里面的内容((CComboBox*)GetDlgItem(IDC_COMBO_CF))->ResetContent();//消除现有所有内容2 如何获取鼠标指针的位置GetWindowRect 详情见657面 超市管理系统 3 如何获取combox下拉列表的索引:int selgetcursel;getlbtext; 4 选中某行某列值并修改SetItemText 5 单击选中listcontrol控件某行右键 添加一个菜单 并触发事件 (见该网页第15条记录) http:/

作为一名IT从业者,你在工作和学习中,遇到哪些问题

大家都是IT从业者,遇到的问题多少与相似. 如果能把这些问题总结下来,并给出解决方案,相信可以帮助很多的人. 我在ITFriend发起了一个话题"作为一名IT从业者,你在工作和学习中,遇到哪些问题",有很多网友给出了很好的答案. 希望对大家有所帮助. 周琦: 首先说说工作上,作为研发,产品需求不断变更,导致不停的重写代码,这时就需要和产品那边进行沟通确定明确的需求了,而且作为研发我们也可以从产品上提出自己的意见和需求.从而引导别人和提高自己上做出更大的提高.  而当遇到测试方面提出的各

有关JAVA基础学习中的集合讨论

    很高兴能在这里认识大家,我也是刚刚接触后端开发的学习者,相信很多朋友在学习中都会遇到很多头疼的问题,希望我们都能够把问题分享出来,把自己的学习思路整理出来,我们一起探讨一起成长.    今天我在这里简单讲解一下我对学习中集合的理解.很多朋友再写解释的时候,没有从最简单说起,造成了阅读中的困惑,或许我能帮助你对集合有一个新的认识.   首先当我们谈到集合的时候要了解一下集合的具体概念. java集合的概念是相对于数组来说的,那么什么是数组呢?   数组:数组是一段连续存储单元. 每个存储单

java学习中,object 对象的使用(toString、equals、hashCode)(java 学习中的小记录)

java学习中,object 对象的使用(java 学习中的小记录)作者:王可利(Star·星星) object 对象(参考API学习) 重点掌握三个方法: 1.toString 返回该对象的字符串表示. 2.equals(object obj)指示其他某个对象是否与这个对象相等. 3.hashCode() 返回对象的哈希码. 详见代码的注释分析(一个是Person类重写方法,一个是Star类使用方法) Star类代码: 1 package study; 2 3 public class sta

Java学习中,常用的命令管理(Java 学习中的小记录)

Java学习中,常用的命令管理      作者:王可利(Star·星星) 一.Window中常见的dos命令 在哪里操作dos命令: Win7 ---> 开始  ---->所有程序--->附件---->命令提示符 Win7-->  开始  --->运行  ---->输入cmd 1.1 盘符的切换: 盘符眀+冒号  格式: 盘符: 例子: 想从C盘到D盘 C:/User/xxxx  D: 1.2 文件夹的操作 dir :显示当前文件夹中的所有文件和文件夹. cd 路

关于Linux学习中的问题和体会

本科期间未开展过与之相关的课程,所以初次接触Linux难免有些问题!参照老师给的学习资料中内容,逐步解决了一些问题,但还有一些问题没解决,下面列举出自己遇到的一些问题. 1.在环境变量与文件查找专题中,使用vim命令代开sh文件,界面处于可编辑状态,但在窗口编辑过程中编辑完后的文件无法保存,,,,,,后来使用手动创建的方式分别创建了sh文件和C语言文件,完成后来的实验!但需要解决的问题是vim命令使用后文件如何保存. 2.在环境变量专题中,对于环境变量的具体作用理解的还不是很透. 3.在软件安装

重写page的OnInit(学习中总结的)

在写b/s框架的系统的时候,我们会发现,我们经常会在不同的网页中验证Session是否存在,,而我这里没有用Session,用的是MemCache技术,其实它就是键值对. 只不过将Memcache中的键,当Cookies中的值存储,然后,验证的时候,返回一步一步获取Memcache中的值. 为了不用每次判断Cookies["sessionid"]是否存在,我们可以把复用代码写在system.Web.UI.Page中的OnInit中, using System; using System