Android语音识别技术、消息推送机制、二维码扫描技术、NDK、JNI

jopen 10年前

一、常用数据结构:数组,堆,栈,队列,链表,树,图,散列表

数组:把具有相同类型的若干变量按有序的形式组织起来。

:是一个特殊的树形数据结构,每个结点都有一个值。一般说的堆是指二叉堆。他的最大特点就是根节点的值最小或最大,并且根节点的两个子树也是一个堆。

:只能在某一端插入和删除的特殊线性表。按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。

队列:一种特殊的线性表,只允许在表的前端进行删除操作,而在表的后端进行插入操作。插入端叫队尾,删除端叫队头。队列是按照先进先出或后进先出的原则组织数据。队列中没有元素的时候,

成为空对列。

链表:是一种物理存储单元上非连续、非顺序的存储结构,既可以表示线性结构,又可以表示非线性结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点组成,结点可以在运行时动态生成。每个结点包括两部分,一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针。

:包含n(n>0)个结点的有穷集合K,在K中定义了一个关系N,N满足以下条件。(1)有且仅有一个结点K0,对于关系N来说没有前驱,称K0为根节点。

(2)除K0外,K中的每个结点,对于关系N来说有且仅有一个前驱。

(3)K中各个结点,对于关系N来说可以有m个

后继。

:是由结点的有穷集合V和边的集合E组成。在图结构中,结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点的是相邻关系。

散列表:如果结构中存在关键字和K相等的记录,则必定在f的存储位置上。不需比较便可直接取得查询记录,称这个关系为散列函数。

二、排序思想

快速排序:它的基本思想是通过一趟扫描后,使得排序序列的长度能大幅度地减少。在冒泡排序中,一次扫描只能确保最大数值的数移到正确位置,而待排序序列的长度可能只减少1。快速排序通过一趟扫描,就能确保某个数(以它为基准点吧)的左边各数都比它小,右边各数都比它大。然后又用同样的方法处理它左右两边的数,直到基准点的左右只有一个元素为止。

选择排序是常用内部排序的一种,常见的实现算法有直接选择排序算法和堆排序算法,选择排序的基本思想是每次从待排数据中选择第n小的数据放到排序列表的第n个位置,假如共有N个数据待排,那么经过N-1次排序后,待排数据就已经按照从小到大的顺序排列了。

直接选择排序算法的思想比较简单:(假设数据放在一个数组a中,且数组的长度是N)

  1:从a[0]-a[N-1]中选出最小的数据,然后与a[0]交换位置

  2:从a[1]-a[N-1]中选出最小的数据,然后与a[1]交换位置(第1步结束后a[0]就是N个数的最小值)

冒泡排序的基本思想是相邻两个元素进行比较,然后交换。第一趟后最后一个数组元素是最大或最小元素,然后对前n-1个数重复如此n-1趟。

  3:从a[2]-a[N-1]中选出最小的数据,然后与a[2]交换位置(第2步结束后a[1]就是N-1个数的最小值)

   以此类推,N-1次排序后,待排数据就已经按照从小到大的顺序排列了。

 插入排序:基本思想,每次将一个待排序的数据元素,插入到前面已经排好序的数列中的适当位置,是数列依然有序;直到待排序列元素插入完为止。

堆排序:是一种树形选择排序,在排序过程中,将数列看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的呢在关系来选择最小的元素。

三、二维条码

什么是二维条码?  

二维条码能够在横向和纵向两个方位同时表达信息,因此能在很小的面积内表达大量的信息。  

二维条码可以分为堆叠式二维条码和矩阵式二维条码。堆叠式二维条码形态上是由多行短截的一维条码堆叠而成;矩阵式二维条码以矩阵的形式组成,在矩阵相应元素位置上用“点”表示二进制“1”,用“空”表示二进制“0”,由“点”和“空”的排列组成代码。  

堆叠式二维条码,有代表性的包括PDF417、Code 49、Code 16K等。矩阵式二维条码有代表性的是Code one、Aztec、Date Matrix、QR码等。

二维条码的特点:

1.高密度编码信息容量大:可容纳多达1850个大写字母或2710个数字或1108个字节,或500多个汉字,比普通条码信息容量约高几十倍。

2.编码范围广:该条码可以把图片、声音、文字、签字、指纹等可以数字化的信息进行编码,用条码表示出来;可以表示多种语言文字;可表示图像数据。

3.容错能力强,具有纠错功能:这使得二维条码因穿孔、污损等引起局部损坏时,照样可以正确得到识读,损毁面积达50%仍可恢复信息。

4.译码可靠性高:它比普通条码译码错误率百万分之二要低得多,误码率不超过千万分之一。

5.可引入加密措施:保密性、防伪性好

6.成本低,易制作,持久耐用。

7.条码符号形状、尺寸大小比例可变

8.二维条码可以使用激光或CCD阅读器识读。

Android上使用Zxing识别条形码和二维码。ZXing是个很经典的条码/二维码识别的开源类库。也可以采用Barcode Scanner。

四、消息推送:

要获取服务器上不定时更新的信息一般来说有两种方法,第一种是客户端使用Pull(拉)的方式,隔一段时间就去服务器上获取信息,看是否有更新的信息出现。第二种就是服务器使用Push(推送)的方式,当服务器端有新信息了,则把最新的信息Push到客户端上。

虽然Pull和Push两种方式都能实现获取服务器端更新信息的功能,但是明显来说Push is better than pull。因为Pull方式更费客户端的网络流量,更主要的是费电量。

Android Cloud to Device Messaging (C2DM)是一个用来帮助开发者从服务器向Android应用程序发送数据的服务。该服务提供了一个简单的、轻量级的机制,允许服务器可以通知移动应用程序直接与服务器进行通信,以便于从服务器获取应用程序更新和用户数据。C2DM服务负责处理诸如消息排队等事务并向运行于目标设备上的应用程序分发这些消息。即后来的GCM,在国内难以使用。

在Android下最有的方式应该采取XMPP协议推送Android信息:

首先介绍一下XMPP基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线探测。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息。

Google官方的C2DM服务器底层也是采用XMPP协议进行的封装。

androidpn是一个基于XMPP协议的java开源Androidpush notification实现。它包含了完整的客户端和服务器端。该服务器端基本是在另外一个开源工程openfire基础上修改实现的。它的实现示意图如下:

androidpn(韩国开发)客户端需要用到一个基于java的开源XMPP协议包asmack,这个包同样也是基于openfire下的另外一个开源项目smack,不过我们不需要自己编译,可以直接把androidpn客户端里面的asmack.jar拿来使用。客户端利用asmack中提供的XMPPConnection类与服务器建立持久连接,并通过该连接进行用户注册和登录认证,同样也是通过这条连接,接收服务器发送的通知。

androidpn服务器端也是java语言实现的,基于openfire开源工程,不过它的Web部分采用的是spring框架,这一点与 openfire是不同的。Androidpn服务器包含两个部分,一个是侦听在5222端口上的XMPP服务,负责与客户端的 XMPPConnection类进行通信,作用是用户注册和身份认证,并发送推送通知消息。另外一部分是Web服务器,采用一个轻量级的HTTP服务器,负责接收用户的Web请求。服务器架构如下:

 

最上层包含四个组成部分,分别是SessionManager,Auth Manager,PresenceManager以及Notification Manager。SessionManager负责管理客户端与服务器之间的会话,Auth Manager负责客户端用户认证管理,Presence Manager负责管理客户端用户的登录状态,NotificationManager负责实现服务器向客户端推送消息功能。

服务器端界面如下,分别对应了上述的几个功能模块:

     发送以后,我们可以在手机端看到接收的消息:

     这个解决方案的最大优势就是简单,我们不需要象C2DM那样依赖操作系统版本,也不会担心某一天Google服务器不可用。利用XMPP协议我们还可以进一步的对协议进行扩展,实现更为完善的功能。

采用这个方案,目前只能发送文字消息,不过对于推送来说一般足够了,因为我们不能指望通过推送得到所有的数据,一般情况下,利用推送只是告诉手机端服务器发生了某些改变,当客户端收到通知以后,应该主动到服务器获取最新的数据,这样才是推送服务的完整实现。

国内的推送服务商:

个推:个推与新浪微博之间实现合作。这大大加强了其知名度。个推通过IP通道实现用户间免费实时通讯服务,支持文字,图片,语音,视频及文件的传输。个推注重的是整体策略的布局,对于企业型APP来说较为实用!

极光:极光推送在推送方面表现出的是短平快,极光推送可以发送消息,效果分析图表等。与此同时,极光推送开通了定制化服务,可以推送时间、用户群、位置等。极光推送更偏重于个人或小团体的APP,灵活、迅速是其优势所在。

蝴蝶:蝴蝶云推送将发展的核心定位在了云端系统,制约蝴蝶云推送发展的,一是云端技术的发展能力;二是地面部队的推广,蝴蝶云推送能否让APP开发者所采用,需要蝴蝶推送团队仔细考量。

智游:针对APP开发,稳定维护长连接是推送平台的一个基础,当运营商在2G2.5G的条件下,出现了网络超龄超负荷,造成信令风暴,以至于刻意缩短空闲连接的释放超时,以起到节省信道资源的目的。智游推送团队为了维护长连接的稳定性,避免在信令风暴出现的时候,保持连接的稳定性,使用了多项核心技术,由于涉及到公司核心业务,需要保密。

个推,1. 第三方客户端集成个推SDK。

2. 第三方客户端启动的时候,调用SDK接口,启动推送服务,SDK后台运行并维护和个推服务端的长连接,实现SDK注册和登录。

3. 第三方服务端调用个推服务器的接口,将要发送的数据通过个推服务器发送到指定身份的个推SDK当中。

4. 个推SDK解析定制数据,并且把第三方服务器透传的数据发送给第三方客户端,第三方客户端根据服务器的数据做出相应的动作或者展现。

五、google语音识别技术

原理

在Android 4.1中,Google加入了被称为“神经网络”的技术,这种技术将语音识别错误率降低了25%以上。当你对你的Android手机说出一个要搜索的关键字时,你的声音会转变成声谱图,被分成8段然后传送到不同的服务器上。Google通过分析以前记录过的无数声谱图,来推测你究竟说了什么。

在这个处理过程中,Google做了两件事:

1,从声谱图中分辨出元音和辅音;

2,从元音和辅音的组合中推测出单词,然后再做进一步处理。这就和你在看见一张图片的时候是一样的:你的大脑总会先寻找这张图片的边缘再看内容。

语音识别,借助于云端技术可以识别用户的语音输入,包括语音控制等技术,使用前需要安装语音识别服务。

Android开发实现:

启动,RecognizerIntent。

设置语言模式

开始语音识别

把语音传至google服务器,云端搜索

搜索完毕,传回数据,得到语音字符

六、JNI

JNI是java NativeInterface,java本地接口。与硬件或操作系统进行交互,提高程序性能会使用C/C++编写的代码,Java代码与其他语言编写的代码进行交互,于是产生了JNI。

书写步骤:

(1)编写带有native声明的方法的类。

(2)javac编译该java类,javah+java类名生成扩展名为h的头文件。

(3)C/C++实现本地方法。(native声明的方法)

(4)将C/C++编写的文件生成动态链接库。

编写java程序:

    Public class HelloWorld{                         Publicnative void dispalyHelloWorld();                         Static{                         System.LoadLibrary(“hello”);                }                Public staticvoid main(String[] args){                         New HelloWorld().displayHelloWorld();                }                }  


编译:Javac HelloWorld.java

生成头文件:Javah HelloWorld

编写本地方法:本地方法名和头文件本地方法名相同。

linux下何谓.so文件:1. 用过windows的同学应该都知道 .dll文件吧, 这二者有什么共通之处呢,其实 .so文件就跟.dll文件差不多.

2.一般来说.so文件就是常说的动态链接库,都是C或C++编译出来的。与Java比较就是:它通常是用的Class文件(字节码).

3.Linux下的.so文件时不能直接运行的,一般来讲,.so文件称为共享库.

4.dll也是由C/C++编写,由VC工具编译。

GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。

 

NDK全称:NativeDevelopment Kit。

1、NDK是一系列工具的集合。

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。这些工具对开发者的帮助是巨大的。[1]

NDK集成了交叉编译器,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

2、NDK提供了一份稳定、功能有限的API头文件声明。

NDK产生so动态链接库供JNI调用。

 

显示大量图片时,如何管理内存?

尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置 一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。

如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常

 

内存溢出解决办法:

(1)      压缩图片

(2)      优化Dalvik虚拟机的堆内存分配,在oncreate方法里面调用下列方法;VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);

(3)及时回收Bitmap对象

(4)HandlerThread(异步加载)+LruCache(内存缓存)+DiskLruCache(硬盘缓存).


来自:http://blog.csdn.net/u010152805/article/details/12852191