当前位置: 移动技术网 > 移动技术>移动开发>Android > Android提高之SurfaceView与多线程的混搭实例

Android提高之SurfaceView与多线程的混搭实例

2019年07月24日  | 移动技术网移动技术  | 我要评论

前文简单介绍了android中surfaceview的基本使用,本文就来介绍一下surfaceview与多线程的混搭。surfaceview与多线程混搭,是为了防止动画闪烁而实现的一种多线程应用。android的多线程用法与java的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解surfaceview与多线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。

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

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

main.xml的源码如下:

<?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">

 <linearlayout android:id="@+id/linearlayout01"
 android:layout_width="wrap_content" android:layout_height="wrap_content">
 <button android:id="@+id/button01" android:layout_width="wrap_content"
  android:layout_height="wrap_content" android:text="单个独立线程"></button>
 <button android:id="@+id/button02" android:layout_width="wrap_content"
  android:layout_height="wrap_content" android:text="两个独立线程"></button>
 </linearlayout>
 <surfaceview android:id="@+id/surfaceview01"
 android:layout_width="fill_parent" android:layout_height="fill_parent"></surfaceview>
</linearlayout>

java程序的源码如下:

package com.testsurfaceview;
import java.lang.reflect.field;
import java.util.arraylist;
import android.app.activity;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.rect;
import android.os.bundle;
import android.util.log;
import android.view.surfaceholder;
import android.view.surfaceview;
import android.view.view;
import android.widget.button;

public class testsurfaceview extends activity {
 /** called when the activity is first created. */
 button btnsinglethread, btndoublethread;
 surfaceview sfv;
 surfaceholder sfh;
 arraylist<integer> imglist = new arraylist<integer>();
 int imgwidth, imgheight;
 bitmap bitmap;//独立线程读取,独立线程绘图

 @override
 public void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 setcontentview(r.layout.main);

 btnsinglethread = (button) this.findviewbyid(r.id.button01);
 btndoublethread = (button) this.findviewbyid(r.id.button02);
 btnsinglethread.setonclicklistener(new clickevent());
 btndoublethread.setonclicklistener(new clickevent());
 sfv = (surfaceview) this.findviewbyid(r.id.surfaceview01);
 sfh = sfv.getholder();
 sfh.addcallback(new mycallback());// 自动运行surfacecreated以及surfacechanged
 }

 class clickevent implements view.onclicklistener {

 @override
 public void onclick(view v) {

  if (v == btnsinglethread) {
  new load_drawimage(0, 0).start();//开一条线程读取并绘图
  } else if (v == btndoublethread) {
  new loadimage().start();//开一条线程读取
  new drawimage(imgwidth + 10, 0).start();//开一条线程绘图
  }
 }
 }
 class mycallback implements surfaceholder.callback {
 @override
 public void surfacechanged(surfaceholder holder, int format, int width,
  int height) {
  log.i("surface:", "change");
 }
 @override
 public void surfacecreated(surfaceholder holder) {
  log.i("surface:", "create");
  // 用反射机制来获取资源中的图片id和尺寸
  field[] fields = r.drawable.class.getdeclaredfields();
  for (field field : fields) {
  if (!"icon".equals(field.getname()))// 除了icon之外的图片
  {
   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);
  }
  }
  // 取得图像大小
  bitmap bmimg = bitmapfactory.decoderesource(getresources(),
   imglist.get(0));
  imgwidth = bmimg.getwidth();
  imgheight = bmimg.getheight();
 }
 @override
 public void surfacedestroyed(surfaceholder holder) {
  log.i("surface:", "destroy");
 }
 }
 /*
 * 读取并显示图片的线程
 */
 class load_drawimage extends thread {
 int x, y;
 int imgindex = 0;

 public load_drawimage(int x, int y) {
  this.x = x;
  this.y = y;
 }
 public void run() {
  while (true) {
  canvas c = sfh.lockcanvas(new rect(this.x, this.y, this.x
   + imgwidth, this.y + imgheight));
  bitmap bmimg = bitmapfactory.decoderesource(getresources(),
   imglist.get(imgindex));
  c.drawbitmap(bmimg, this.x, this.y, new paint());
  imgindex++;
  if (imgindex == imglist.size())
   imgindex = 0;
  sfh.unlockcanvasandpost(c);// 更新屏幕显示内容
  }
 }
 };
 /*
 * 只负责绘图的线程
 */
 class drawimage extends thread {
 int x, y;
 public drawimage(int x, int y) {
  this.x = x;
  this.y = y;
 }
 public void run() {
  while (true) {
  if (bitmap != null) {//如果图像有效
   canvas c = sfh.lockcanvas(new rect(this.x, this.y, this.x
    + imgwidth, this.y + imgheight));

   c.drawbitmap(bitmap, this.x, this.y, new paint());

   sfh.unlockcanvasandpost(c);// 更新屏幕显示内容
  }
  }
 }
 };
 /*
 * 只负责读取图片的线程
 */
 class loadimage extends thread {
 int imgindex = 0;
 public void run() {
  while (true) {
  bitmap = bitmapfactory.decoderesource(getresources(),
   imglist.get(imgindex));
  imgindex++;
  if (imgindex == imglist.size())//如果到尽头则重新读取
   imgindex = 0;
  }
 }
 };
}

希望本文所述示例能对大家进行android的surfaceview与多线程的混搭编程有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网