SurfaceView

如果你的游戏不吃CPU,用View就比较好,符合标准 Android操作方式,由系统决定刷新surface的时机。

  但如果很不幸的,你做不到不让你的程序吃CPU,你就只好使用SurfaceView来强制刷新surface了,不然系统的UI进程很可能抢不过你那些吃CPU的线程。

  当然其实不止这两种方法来刷新Surface的,这两种只是纯Java应用比较常见的方法。

  SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面而View必须在UI的主线程中更新画面。

  那么在UI的主线程中更新画面 可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。

   当使用surfaceView 由于是在新的线程中更新画面所以不会阻塞你的UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要surfaceView中 thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

  所以基于以上,根据游戏特点,一般分成两类。

  1 被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

  2 主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

 

SurfaceView 由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,网上介绍 SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用SurfaceHolder的lockCanvas和 unlockCanvasAndPost。

Android的大多数控件都是继承自View的,因此在自定义控件时一般也是继承View类,但是对于高效的,游戏级别的绘图,或者是播放器等要求比较高的地方,普通的View类就有点吃不开了,这个时候就要用到SurfaceView类。因为比较高级,单纯一个继承自SurfaceView类是不行的,必须实现一个SurfaceHolder.Callback接口来指明SurfaceView创建、改变、删除时的回调方法,并且在SurfaceView中通过一个SurfaceHolder对象来控制SurfaceView。如果将该SurfaceView作为某个Activity的全屏View,则直接调用setContentView(new MyView());就好了;但若是作为屏幕View的一部份,就应该修改对应的layout XML文件

了,添加类似的布局代码:
    <com.example.fq.MyView
    android:id="@+id/sv"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    />
其中com.example.fq.MyView为对应自定义类的全名。
由于默认的XML文件解析方法是调用View的View(Context , AttributeSet )构造函数构造View,因此你的自定义SurfaceView中也应该有一个参数为(Context , AttributeSet )

的构造函数,并且在构造函数中执行父类的对应函数super( Context , AttributeSet )。

在绘图时,必须首先用Canvas c=holder.lockCanvas();锁定并获得画布,随后进行绘制,再调用holder.unlockCanvasAndPost(c);将绘制内容进行呈现

SurfaceView它用于显示,SurfaceHolder就是用于用来管理这个显示的SurfaceView对象的,但在SurfaceHolder是怎么样去管理这个对象的呢?这就用到了SurfceHolder.addCallback()方法添加一个SurfaceHolder接口的内部接口的三个抽象方法用于管理或者说是用于监听SurfaceView。这样就达到了管理SurfaceView的目的。

package cn.com.sxp;
import android.app.Activity;
import android.os.Bundle;
public class SurfaceViewActivity extends Activity {
    private sxpView sv= null;
    /** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        sv =(cn.com.sxp.sxpView)findViewById(R.id.sxpView);
    }
}
 

以前用自带的控件用多了,都习惯写上(Button)find....其实也可以自己定义控件,将xml文件布局控件与程序控件联系起来,只是要写上自定义控件的全路径。

surfaceView文件

package cn.com.sxp;
import java.util.Vector;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class sxpView extends SurfaceView implements SurfaceHolder.Callback {
    // 实现SurfaceHolder.Callback接口,到时候surfaceView被创建、销毁什么的,都会调用这个接口的回调方法.

    // A client may implement this interface to receive information about changes to the surface. When used with a SurfaceView, the 
//Surface being held is only 

    // available between calls to surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder). The Callback is set with 
//SurfaceHolder.addCallback method. 

    // 每个surfaceView都要有surfaceHolder这么个组件,这个组件用来控制和访问surfaceView

    private SurfaceHolder sh = null; // 专门用于控制surfaceView的

    private Vector<Float> xAxis = new Vector<Float>();
    private Vector<Float> yAxis = new Vector<Float>();
    // XML文件解析需要调用View的构造函数View(Context , AttributeSet)因此自定义SurfaceView中也需要该构造函数

    public sxpView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub

        // 是surfaceView的一个方法. Return the SurfaceHolder providing access and control over this SurfaceView's underlying surface.
        
        sh = getHolder();
        // Add a Callback interface for this holder. There can several Callback interfaces associated with a holder.

        // addCallback方法就是指定了surfaceChanged等方法称为回调函数; 而所谓的实现SurfaceHolder.Callback接口就是让你实现surfaceChanged等接口

        sh.addCallback(this);
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub


    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        new Thread(new sxpLoop()).start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }
    public void doDraw(Canvas canvas) {
        // TODO Auto-generated method stub

        super.onDraw(canvas);
        canvas.drawColor(Color.GRAY);// 这里是绘制背景

        Paint p = new Paint(); // 笔触

        p.setAntiAlias(true); // 反锯齿

        p.setColor(Color.BLUE);
        p.setStyle(Style.STROKE);
        for (int i = 0; i < xAxis.size(); i++)
            canvas.drawCircle(xAxis.elementAt(i), yAxis.elementAt(i), 10, p);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub

        // Implement this method to handle touch screen motion events.

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            xAxis.add(event.getX());
            yAxis.add(event.getY());
        }
        return true;
    }
    class sxpLoop implements Runnable {
        @Override
        public void run() {
            // TODO Auto-generated method stub

            while (true) {
                try {
                    // 在绘图时,必须首先用Canvas c=holder.lockCanvas();锁定并获得画布,随后进行绘制,再调用holder.unlockCanvasAndPost(c);将绘制内容进行呈现

                    Canvas c = sh.lockCanvas();
                    doDraw(c);
                    sh.unlockCanvasAndPost(c);
                    Thread.sleep(20);
                } catch (Exception e) {
                }
            }
        }
    }

}

自定义的控件必须要继承surfaceView类,同时实现surfaceHolder.Callback接口。surfaceView就是通过这个接口来控制的,什么接口,就是类似于onCreated...等。代码中还有个addCallback(this),就是增加这个自定义类作为参数,学术上叫做添加接口,个人呢理解就是onCreated...几个接口在自定义类中实现,所以就添加这个类作为参数了。

 

布局文件

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=http://schemas.android.com/apk/res/android

    android:layout_width="fill_parent"
 

    android:layout_height="fill_parent"

    android:orientation="vertical" >

    <!-- 这种用法应该学习,布局中摆放的是控件,也可以摆放我自定义的控件. 但是我要指明我的控件的包名与空间名. 系统自带的控件不需要指定包名 -->

    <cn.com.sxp.sxpView

    android:id="@+id/sxpView"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    />


</LinearLayout>

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值