Android提高之SurfaceView与多线程的混搭实例
程序员文章站
2022-11-05 17:07:48
前文简单介绍了android中surfaceview的基本使用,本文就来介绍一下surfaceview与多线程的混搭。surfaceview与多线程混搭,是为了防止动画闪烁...
前文简单介绍了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与多线程的混搭编程有所帮助。