热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

21天学习android开发教程之SurfaceView与多线程的混搭

21天学习android开发教程之SurfaceView与多线程的混搭,感兴趣的小伙伴们可以参考一下

上一篇简单介绍了SurfaceView的基本使用,这次就介绍SurfaceView与多线程的混搭。SurfaceView与多线程混搭,是为了防止动画闪烁而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。
        本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

 

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



    
        

本文程序的源码:

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 imgList = new ArrayList();
    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软件编程有所帮助。


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文探讨了 RESTful API 和传统接口之间的关键差异,解释了为什么 RESTful API 在设计和实现上具有独特的优势。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何解决MyBatis中常见的BindingException错误,提供了多种排查和修复方法,确保Mapper接口与XML文件的正确配置。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
author-avatar
悶得咪_438
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有