Android提高第三篇之SurfaceView与多线程的混搭

来源:互联网 发布:ios 面向切面编程 编辑:程序博客网 时间:2024/04/24 15:29
     上一篇简单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。

       本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都“边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。

main.xml的源码:

01.<?xml version="1.0" encoding="utf-8"?>  02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  03.    android:layout_width="fill_parent" android:layout_height="fill_parent"  04.    android:orientation="vertical">  05.  06.    <LinearLayout android:id="@+id/LinearLayout01"  07.        android:layout_width="wrap_content" android:layout_height="wrap_content">  08.        <Button android:id="@+id/Button01" android:layout_width="wrap_content"  09.            android:layout_height="wrap_content" android:text="单个独立线程"></Button>  10.        <Button android:id="@+id/Button02" android:layout_width="wrap_content"  11.            android:layout_height="wrap_content" android:text="两个独立线程"></Button>  12.    </LinearLayout>  13.    <SurfaceView android:id="@+id/SurfaceView01"  14.        android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>  15.</LinearLayout> 

 

本文程序的源码:

01.package com.testSurfaceView;  02.  03.import java.lang.reflect.Field;  04.import java.util.ArrayList;  05.import android.app.Activity;  06.import android.graphics.Bitmap;  07.import android.graphics.BitmapFactory;  08.import android.graphics.Canvas;  09.import android.graphics.Paint;  10.import android.graphics.Rect;  11.import android.os.Bundle;  12.import android.util.Log;  13.import android.view.SurfaceHolder;  14.import android.view.SurfaceView;  15.import android.view.View;  16.import android.widget.Button;  17.  18.public class testSurfaceView extends Activity {  19.    /** Called when the activity is first created. */  20.    Button btnSingleThread, btnDoubleThread;  21.    SurfaceView sfv;  22.    SurfaceHolder sfh;  23.    ArrayList<Integer> imgList = new ArrayList<Integer>();  24.    int imgWidth, imgHeight;  25.    Bitmap bitmap;//独立线程读取,独立线程绘图  26.  27.    @Override  28.    public void onCreate(Bundle savedInstanceState) {  29.        super.onCreate(savedInstanceState);  30.        setContentView(R.layout.main);  31.  32.        btnSingleThread = (Button) this.findViewById(R.id.Button01);  33.        btnDoubleThread = (Button) this.findViewById(R.id.Button02);  34.        btnSingleThread.setOnClickListener(new ClickEvent());  35.        btnDoubleThread.setOnClickListener(new ClickEvent());  36.        sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);  37.        sfh = sfv.getHolder();  38.        sfh.addCallback(new MyCallBack());// 自动运行surfaceCreated以及surfaceChanged  39.    }  40.  41.    class ClickEvent implements View.OnClickListener {  42.  43.        @Override  44.        public void onClick(View v) {  45.  46.            if (v == btnSingleThread) {  47.                new Load_DrawImage(0, 0).start();//开一条线程读取并绘图  48.            } else if (v == btnDoubleThread) {  49.                new LoadImage().start();//开一条线程读取  50.                new DrawImage(imgWidth + 10, 0).start();//开一条线程绘图  51.            }  52.  53.        }  54.  55.    }  56.  57.    class MyCallBack implements SurfaceHolder.Callback {  58.  59.        @Override  60.        public void surfaceChanged(SurfaceHolder holder, int format, int width,  61.                int height) {  62.            Log.i("Surface:", "Change");  63.  64.        }  65.  66.        @Override  67.        public void surfaceCreated(SurfaceHolder holder) {  68.            Log.i("Surface:", "Create");  69.  70.            // 用反射机制来获取资源中的图片ID和尺寸  71.            Field[] fields = R.drawable.class.getDeclaredFields();  72.            for (Field field : fields) {  73.                if (!"icon".equals(field.getName()))// 除了icon之外的图片  74.                {  75.                    int index = 0;  76.                    try {  77.                        index = field.getInt(R.drawable.class);  78.                    } catch (IllegalArgumentException e) {  79.                        // TODO Auto-generated catch block  80.                        e.printStackTrace();  81.                    } catch (IllegalAccessException e) {  82.                        // TODO Auto-generated catch block  83.                        e.printStackTrace();  84.                    }  85.                    // 保存图片ID  86.                    imgList.add(index);  87.                }  88.            }  89.            // 取得图像大小  90.            Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  91.                    imgList.get(0));  92.            imgWidth = bmImg.getWidth();  93.            imgHeight = bmImg.getHeight();  94.        }  95.  96.        @Override  97.        public void surfaceDestroyed(SurfaceHolder holder) {  98.            Log.i("Surface:", "Destroy");  99.  100.        }  101.  102.    }  103.  104.    /* 105.     * 读取并显示图片的线程 106.     */  107.    class Load_DrawImage extends Thread {  108.        int x, y;  109.        int imgIndex = 0;  110.  111.        public Load_DrawImage(int x, int y) {  112.            this.x = x;  113.            this.y = y;  114.        }  115.  116.        public void run() {  117.            while (true) {  118.                Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  119.                        + imgWidth, this.y + imgHeight));  120.                Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  121.                        imgList.get(imgIndex));  122.                c.drawBitmap(bmImg, this.x, this.y, new Paint());  123.                imgIndex++;  124.                if (imgIndex == imgList.size())  125.                    imgIndex = 0;  126.  127.                sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  128.            }  129.        }  130.    };  131.  132.    /* 133.     * 只负责绘图的线程 134.     */  135.    class DrawImage extends Thread {  136.        int x, y;  137.  138.        public DrawImage(int x, int y) {  139.            this.x = x;  140.            this.y = y;  141.        }  142.  143.        public void run() {  144.            while (true) {  145.                if (bitmap != null) {//如果图像有效  146.                    Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  147.                            + imgWidth, this.y + imgHeight));  148.  149.                    c.drawBitmap(bitmap, this.x, this.y, new Paint());  150.  151.                    sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  152.                }  153.            }  154.        }  155.    };  156.  157.    /* 158.     * 只负责读取图片的线程 159.     */  160.    class LoadImage extends Thread {  161.        int imgIndex = 0;  162.  163.        public void run() {  164.            while (true) {  165.                bitmap = BitmapFactory.decodeResource(getResources(),  166.                        imgList.get(imgIndex));  167.                imgIndex++;  168.                if (imgIndex == imgList.size())//如果到尽头则重新读取  169.                    imgIndex = 0;  170.            }  171.        }  172.    };  173.}  

本文来自:http://blog.csdn.net/hellogv/article/details/5986835