Android-使用SurfaceView多线程绘制动画

        使用SurfaceView中的Surface对象进行绘图,其本质就是利用SurfaceHolder的lockCanvas获取到Canvas对象进行绘制的,对于绘制动画来说,必须使用双缓冲,或者采用双线程,一个线程负责专门的预处理,比如图片数据读取,另外一个线程负责进行专绘制图形。因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。

下在给出一个例子,讲解一下如何利用双线程提高绘图速度:

以下可以看到的动画是一张解码后的图片从最屏幕最左边快速移到右边,重新开始则清屏进行显示

package com.test.surfaceview;

import java.lang.reflect.Field;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class TestsurfaceviewActivity extends Activity {
	private final static String TAG = "TestsurfaceviewActivity";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		// setContentView(new MySurfaceView(this)); // 这里以MySurfaceView作为显示View
		onTestInit();
	}

	private SurfaceView drawSV = null;
	private SurfaceHolder drawSH = null;
	ArrayList<Integer> imgList = new ArrayList<Integer>(); 
	private int mWidth= 0, mHeight = 0;
	private Bitmap bitmap = null;
	private LoadImage loadImg = new LoadImage();
	private DrawImage drawImg = null;

	private void onTestInit() {
		drawSV = (SurfaceView) this.findViewById(R.id.SurfaceDrawView);
		drawSH = drawSV.getHolder();
		drawSH.addCallback(new MySVCallback());
	}
	
	private int onTestStart(){
		if(loadImg != null){
			loadImg.start();			
		}
		drawImg = new DrawImage(0,mHeight);
		drawImg.start();
		return 0;
	}
	
	private void onTestStop(){
		if(loadImg != null){
			loadImg.stop();
		}
		
		if(drawImg != null){
			drawImg.stop();
		}
	}

	private class MySVCallback implements SurfaceHolder.Callback {
		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			// TODO Auto-generated method stub
			Log.i(TAG, "surfaceChanged is called");
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			Log.i(TAG, "surfaceCreated is called");
			// 用反射机制来获取资源中的图片ID和尺寸
			Field[] fields = R.drawable.class.getDeclaredFields();
			for (Field field : fields) {
				// 除了icon及launcher之外的图片
				if (!"icon".equals(field.getName())
						&& !"ic_launcher".equals(field.getName())) {
					int index = 0;
					try {
						index = field.getInt(R.drawable.class);
					} catch (IllegalArgumentException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					// 保存图片ID
					imgList.add(index);
				}
			}
			
			Log.i(TAG,"imglist size = "+imgList.size());
            // 取得图像大小  
            Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
                    imgList.get(0));

            mWidth  = bmImg.getWidth(); 
            mHeight = bmImg.getHeight();
            
            onTestStart();
		}

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

	private class LoadImage extends Thread {
		private int imgIndex = 0;

		public void run() {
			while (true) {
				bitmap = BitmapFactory.decodeResource(getResources(),
						imgList.get(imgIndex));
				++imgIndex;
				if (imgIndex == imgList.size()) { // 循环取图片数据
					imgIndex = 0;
				}
			}
		}
	}
	
	private class DrawImage extends Thread{
		private int x,y;
		public DrawImage(int x,int y){
			this.x = x;
			this.y = y;
		}
		
		private void ClearScreen(){
			Canvas canvas = drawSH.lockCanvas(null);
			canvas.drawColor(Color.BLACK);// 清除画布
			drawSH.unlockCanvasAndPost(canvas);
		}
		
		public void run() {
			while (true) {
				if (bitmap != null) {
					/**
					 * 以下两个有明显的效率差异,lockCanvas()指定Rect内减少循环画线的次数,
					 * 可以提高绘图效率,全屏刷新时会很闪烁
					 */
					Canvas c = drawSH.lockCanvas(new Rect(this.x, this.y,
							this.x + mWidth, this.y + mHeight));
//					Canvas c = drawSH.lockCanvas();
					c.drawBitmap(bitmap, this.x, this.y, new Paint());
					drawSH.unlockCanvasAndPost(c);// 将显示内容上屏
					
					this.x += 10;
					//如果到了终点,则清屏重来
					if(this.x > 1280 - mWidth){
						this.x = 0;
						ClearScreen();
					}
				}
			}
		}
	}
}

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值