文档章节

Android学习笔记-Lesson 6: Cannon Game APP

勤奋的桑尼
 勤奋的桑尼
发布于 2014/09/18 16:28
字数 2255
阅读 15
收藏 0

知识点:

1、multithreading

2、surface view

3、drawing with paint and canvas

4   simple collision detection

5.  soundpool and audiomanager

6. Fragment lifecycle

Technologies Overview

1. Attaching Custom Views to Layouts

2. res/raw folders

3. Fragment and Activity

1、 资源中带有变量的strings.xml

<string name="results_format">Shots fired: %1$d\nTotal time: %2$.1f</string>

       其中,%表示后面是变量,如果只有一个变量,则直接用%d或%.1f即可,多个变量,需要在中间加1$和2$来区分。

2、设置音量按钮控制游戏音量

setVolumeControlStream(AudioManager.STREAM_MUSIC);

3、SparseIntArray : SparseArray是android里为<Interger,Object>这样的Hashmap而专门写的class,目的是提高效率,其核心是折半查找函数(binarySearch)

    http://developer.android.com/reference/android/util/SparseIntArray.html

    与hashMap的对比:

    

  • Memory usage for a SparseIntArray will be roughly a factor of 10 less that for an equivalent HashMap. This is due to a combination of things:

    (However, if you create the Integer objects the right way, the "boxing" overhead can be mitigated by the effects of the Integer classes instance cache.)

    By contrast, the sparse version requires 2 * capacity 4 byte words.

    • the hash table array holds roughly 1 reference per entry (depending on how full the table is ...),

    • the keys and values have to be "boxed" as Integer objects in a HashMap, and

    • each entry in a HashMap requires a "node" object that is fairly heavy weight - 4 fields in the standard implementation.

  • Lookup (i.e. get) is O(logN) compared with O(1) for a HashMap.

  • Random insertion is O(N) compared with O(1) for a HashMap. (This is because an insertion has to move on average half of the existing entries so that the new entry can be added at the correct position in the arrays.)

  • Sequential insertion (i.e. in ascending in key order) is O(1).


4. SoundPool :引自 http://www.devdiv.com/Android-SoundPool%E7%B1%BB%E7%9A%84%E4%BD%BF%E7%94%A8-thread-130200-1-1.html

        SoundPool类是Android用于管理和播放应用程序的音频资源的类。一个SoundPool对象可以看作是一个可以从APK中导入资源或者从文件系统中载入文件的样本集合。它利用MediaPlayer服务为音频解码为一个原始16位PCM流。这个特性使得应用程序可以进行流压缩,而无须忍受在播放音频时解压所带来的CPU负载和时延。

        此外对于低延迟播放,SoundPool还可以管理多个音频流。当SoundPool对象构造时,maxStreams参数的设置表示的是在单一的SoundPool中,同一时间所能播放流的最大数量。利用SoundPool可以跟踪活跃的流的数量。如果其数量超过流的最大数目,SoundPool会基于优先级自动停止先前播放的流。限制流的最大数目,有助于减轻CPU的负荷,减少音频混合对视觉和UI性能的影响。

        声音可以通过设置一个非零的循环价值循环。如果值为-1将导致声音永远循环。在这种情况下,应用程序必须明确地调用stop()函数,以停止声音。其他非零值将导致声音按指定数量的时间重复。

        在SoundPool中,播放速率也可以改变。1.0的播放率可以使声音按照其原始频率(如果必要的话,将重新采样硬件输出频率)。而2.0的播放速率,可以使声音按照其原始频率的两倍播放。如果为0.5的播放率,则播放速率是原始频率的一半。播放速率的取值范围是0.5至2.0。

        优先级的运行从低到高排列的。当用户调用play()函数时,如果活跃的流数目大于规定的maxStreams参数,流分配器将会结束优先级最低的流。如果有多条流都处于最低优先级,优先级系统将会选择关闭最老的流。

        一旦声音被成功加载和播放,应用程序可以调用SoundPool.play()来触发的声音。播放过程中的流可又被暂停或继续播放。应用程序还可以通过调整播放率改变音高。

        注意,由于资源的限制,流可以被停止,streamID是一个对特定流实例的引用。如果流被停止并且允许更高优先级的流播放,流就不再有效了。然而,应用程序允许调用没有错误的streamID方法。因为如果应用程序不需要关心流的生命周期,这可能有助于简化程序逻辑。   

适用场合

        SoundPool在载入声音文件过程中,使用了单独的线程,不会对视觉和UI性能产生影响。但是由于SoundPool对载入声音文件大小有所限制,这就导致了如果SoundPool没有载入完成,而不能安全调用play方法。好在Android SDK提供了一个SoundPool.OnLoadCompleteListener类来帮助我们了解声音文件是否载入完成,用户只须重载 onLoadComplete(SoundPool soundPool, int sampleId, int status) 方法即可实现。

    与MediaPlayer相比,MediaPlayer存在着资源占用量较高、延迟时间较长、不支持多个音频同时播放等缺点,但SoundPool本身由于内存资源申请有严格限制,所以在开发过程中,笔者建议尽量用SoundPool来播放一些较短的声音片段或者音效。

DEMO

1)SoundPool对象初始化

        我们可以调用SoundPool的构造函数public SoundPool (int maxStreams, int streamType, int srcQuality)来初始化SoundPool对象。

        其中参数说明如下:

        maxStreams:指定支持多少个声音,SoundPool对象中允许同时存在的最大流的数量。

        streamType:制定声音类型,流类型可以分为STREAM_VOICE_CALL, STREAM_SYSTEM, STREAM_RING,STREAM_MUSIC 和 STREAM_ALARM四种类型。在AudioManager中定义。

        srcQuality:指定声音品质(采样率变换质量)。目前没有用到,可以设为0。

        2)载入声音资源

        调用load方法载入声音资源,SoundPool提供了4个Load方法,比较常用的是以下两个:

        Public int load(Context context, int resId, int priority):从resId所对应的资源加载声音。

        Public int load(String path, int priority):从path对应的文件中加载声音。

        上面两个方法中都有一个priority参数,该参数目前还没有任何作用,Android建议将该参数设置为1,保持和未来的兼容性。

同时,这两个方法加载声音之后,都会返回该声音的ID,以后程序就可以通过该声音的ID来播放指定声音。

        3)播放控制

        要播放SoundPool中的声音,须调用int play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)方法。

        其中参数说明如下:

        soundID:Load()函数返回的声音ID号。

        leftVolume:左声道音量设置。

        rightVolume:右声道音量设置。

        priority:指定播放声音的优先级,数值越高,优先级越大。

        loop:指定是否循环。-1表示无限循环,0表示不循环,其他值表示要重复播放的次数。

        rate:指定播放速率。1.0的播放率可以使声音按照其原始频率。而2.0的播放速率,可以使声音按照其原始频率的两倍播放。如果为0.5的播放率,则播放速率是原始频率的一半。播放速率的取值范围是0.5至2.0。

        4)释放资源

        播放结束,我们可以调用release()方法释放所有SoundPool对象占据的内存和资源。

    5)实例分析

import java.util.HashMap;

import android.app.Activity;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {
        
        Button bombButton;
        Button shotButton;
        Button arrowButton;
        Button allButton;
        
        SoundPool mSoundPool = null;
        
        HashMap<Integer, Integer> soundMap = new HashMap<Integer, Integer>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        bombButton = (Button) findViewById(R.id.bomb);
        shotButton = (Button) findViewById(R.id.shot);
        arrowButton = (Button) findViewById(R.id.arrow);
        allButton = (Button) findViewById(R.id.all);
        
                //设置最多可容纳10个音频流,音频的品质为5
        mSoundPool = new SoundPool(10, AudioManager.STREAM_SYSTEM, 5);
                //load方法加载指定音频文件,并返回所加载的音频ID。此处使用HashMap来管理这些音频流
                soundMap.put(1 , mSoundPool.load(this, R.raw.bomb , 1));
                soundMap.put(2 , mSoundPool.load(this, R.raw.shot , 1));
                soundMap.put(3 , mSoundPool.load(this, R.raw.arrow , 1));
                
                bombButton.setOnClickListener(this);
                shotButton.setOnClickListener(this);
                arrowButton.setOnClickListener(this);
                allButton.setOnClickListener(this);
    }
    
        //重写OnClickListener监听器接口的方法
        @Override
        public void onClick(View v) {
                // TODO Auto-generated method stub
                //判断哪个按钮被单击
                switch (v.getId()) {
                case R.id.bomb:
                        mSoundPool.play(soundMap.get(1), 1, 1, 0, 0, 1);
                        break;
                case R.id.shot:
                        mSoundPool.play(soundMap.get(2), 1, 1, 0, 0, 1);
                        break;
                case R.id.arrow:
                        mSoundPool.play(soundMap.get(3), 1, 1, 0, 0, 1);
                        break;
                case R.id.all:
                        mSoundPool.play(soundMap.get(1), 1, 1, 0, 0, 1);
                        mSoundPool.play(soundMap.get(2), 1, 1, 0, 0, 1);
                        mSoundPool.play(soundMap.get(3), 1, 1, 0, 0, 1);
                default:
                        break;
                }
        }

}

 通常,为了更好地管理SoundPool所加载的每个声音的ID,程序一般会使用一个HashMap<Integer,Integer>对象来管理声音。按照上面的步骤初始化,载入声音,并且把按钮绑定监听器,点击按钮播放相应声音。

5. 判断触屏的角度

// aligns the cannon in response to a user touch
	public double alignCannon(MotionEvent event) {
		// get the location of the touch in this view
		Point touchPoint = new Point((int) event.getX(), (int) event.getY());

		// compute the touch's distance from center of the screen
		// on the y-axis
		double centerMinusY = (screenHeight / 2 - touchPoint.y);

		double angle = 0; // initialize angle to 0

		// calculate the angle the barrel makes with the horizontal
		if (centerMinusY != 0) // prevent division by 0
			angle = Math.atan((double) touchPoint.x / centerMinusY);

		// if the touch is on the lower half of the screen
		if (touchPoint.y > screenHeight / 2)
			angle += Math.PI; // adjust the angle

		// calculate the endpoint of the cannon barrel
		barrelEnd.x = (int) (cannonLength * Math.sin(angle));
		barrelEnd.y = (int) (-cannonLength * Math.cos(angle) + screenHeight / 2);

		return angle; // return the computed angle
	} // end method alignCannon

© 著作权归作者所有

勤奋的桑尼
粉丝 1
博文 32
码字总数 32516
作品 0
徐汇
程序员
私信 提问
Android实战经验之图像处理及特效处理的集锦(总结版)

1 Android学习笔记进阶之在图片上涂鸦(能清屏) 2 Android学习笔记之详细讲解画圆角图片 3 Android学习笔记进阶20之得到图片的缩略图 4 Android学习笔记进阶19之给图片加边框 5 Android学习笔...

xiaosi
2012/03/12
40.1K
25
Android--面试中遇到的问题总结(三)

《Android 开发工程师面试指南 LearningNotes 》,作者是陶程,由梁观全贡献部分。大家可以去知乎关注这两位用心的少年。这份指南包含了大部分Android开发的基础、进阶知识,不仅可以帮助准备...

sealin
2017/02/22
0
0
一份关于 Java、Kotlin 与 Android 的学习笔记

JavaKotlinAndroidLearn 这是一份关于 Java 、Kotlin 、Android 的学习笔记,既包含对基础知识点的介绍,也包含对一些重要知识点的源码解析,笔记的大纲如下所示: Java 重拾Java(0)-基础知...

叶应是叶
2018/08/08
0
0
各位大侠们,根据你们的建议 我稍作修改了一下我的简历 你们看行吗?

我目前所在地是 河南商丘, 工作的目标地是 深圳附近。 我在 性格方面 是一个乐观积极的人,动手能力强,喜欢钻研。我在 能力方面 是一个负责并充满能量的年轻人,不懂就学,不会就问问,问百...

farley-fu
2014/09/05
1K
20
仿安智市场UI框架布局之fragment+tabhost底部菜单

第一部分就是你们现在看的这个贴,主要功能:实现fragment_+tabhost来搭建整个app的大体UI框架,底部是一个可切换的选项卡(安智市场中的底部选项卡的切换动画效果略过,没写,太困了,码完字...

chengche
2013/12/06
3.5K
5

没有更多内容

加载失败,请刷新页面

加载更多

刚哥谈架构 (二) 我眼中的架构师

之前在公司,有小伙伴在向别人介绍我的时候,经常会有人这么说:“刚哥是我们的architcture”,如果来人是老外,心中一定是一惊,心中暗叹,“这位匪首看上去貌不惊人,难道已经做到了架构和...

naughty
40分钟前
3
0
OSChina 周日乱弹 —— 别问,问就是没空

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @tom_tdhzz :#今日歌曲推荐# 分享容祖儿/彭羚的单曲《心淡》: 《心淡》- 容祖儿/彭羚 手机党少年们想听歌,请使劲儿戳(这里) @wqp0010 :周...

小小编辑
今天
111
4
golang微服务框架go-micro 入门笔记2.1 micro工具之micro api

micro api micro 功能非常强大,本文将详细阐述micro api 命令行的功能 重要的事情说3次 本文全部代码https://idea.techidea8.com/open/idea.shtml?id=6 本文全部代码https://idea.techidea8....

非正式解决方案
今天
5
0
Spring Context 你真的懂了吗

今天介绍一下大家常见的一个单词 context 应该怎么去理解,正确的理解它有助于我们学习 spring 以及计算机系统中的其他知识。 1. context 是什么 我们经常在编程中见到 context 这个单词,当...

Java知其所以然
昨天
5
0
Spring Boot + Mybatis-Plus 集成与使用(二)

前言: 本章节介绍MyBatis-Puls的CRUD使用。在开始之前,先简单讲解下上章节关于Spring Boot是如何自动配置MyBatis-Plus。 一、自动配置 当Spring Boot应用从主方法main()启动后,首先加载S...

伴学编程
昨天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部