Android高级终端开发学习笔记(《疯狂Android讲义》第11章-第17章)

Posted wyy_persist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android高级终端开发学习笔记(《疯狂Android讲义》第11章-第17章)相关的知识,希望对你有一定的参考价值。

Android高级终端开发笔记

2021/6/19 下午 13:34开始

  1. 多媒体应用开发

android支持的音频格式有:MP3 WAV 3GP等。支持的视频格式有MP4 3GP等。

多媒体数据既可以来自android应用的资源文件,也可以来自外部存储器上的文件,还可以是来自网络的文件流。

android也提供了对摄像头 麦克风的支持。

11.1 音频和视频的播放

11.1.1 android 9增强的MediaPlayer

使用MediaPlayer装载音频文件完成之后,调用MediaPlayer对象的三个方法进行播放:

Start()函数,开始和回复播放

Stop()函数,停止播放

Pauser()函数,暂停播放

装载文件的时候,mediaplayer对象提供了如下的静态方法:

Create(Context context, Uri uri)函数,从指定的Uri装载音频文件,并返回创建的MediaPlayeru对象

Create(Context context,int resid)函数,从制定的资源文件id来装载音频文件,并返回MediaPlayer对象。

当需要循环播放多个音频文件的时候,使用MediaPlayer对象的setDataSource()方法来制定播放的音频文件的。

setDataSource(String path)函数,装载path路径代表的文件。

setDataSource(FileDecriptor fd,long offset,long length)函数,制定装载fd做代表的文件中从offset开始,长度为length的文件内容。

setDataSource(FileDecriptor fd),制定转载fd多代表的文件。

setDataSource(Context context,Uri uri)方法之后,指定装载uri所代表的文件。

使用上述的setDataSource()方法之后,MediaPlayer对象并没有真正地装载文件,需要使用其中的prepare()方法准备音频。(就是真正地装载音频文件)

Mediaplayer对象还提供了一些监听播放事件的方法:

setOnCompletionListener()方法为mediaPlayer对象增加播放完成事件绑定事件监听器。

setOnErrorListener()方法为该对象的播放错误事件绑定事件监听器。

setOnPreparedListener()方法为mediaplayer对象调用prepare()方法触发该监听器。

setOnSeekCompleteListener()方法,当mediaplayer对象调用seek()或seekTo()方法时候触发该监听器。

归纳一下使用MediaPlayer对象播放不同来源的音频文件:

播放应用的资源文件

1.调用MediapLayer对象的create()方法装载指定的资源文件。

  1. 调用MediaPlayer对象的start() pause() stop()方法实现播放控制功能。

播放应用的原始资源文件

  1. 调用context对象的getAssets()方法获得应用的AssetManager。
  2. 调用AssetManager对象的openFd(String name)方法打开指定的原始资,该方法返回一个AssetFileDescriptor对象。
  3. 调用MediaPlayer对象(或者利用已有的MediaPlayer对象),并调用MediapLayer对象的setDataSource(FileDescriptor fd,long offset,long length)方法来装载音频资源。
  4. 调用mediaPlayer对象的prepare()方法准备音频。
  5. 调用mediaPlayer对象的start() pause() stop()方法来实现对音频文件的控制播放。

注意:使用openFd()方法打开资源的时候,不管是哪一个,使用MediaPlayer播放的时候总是从资源的第一个开始。

播放外部存储器上的音频文件

  1. 创建mediaplayer对象,并调用MediaPlayer对象的setDataSource()方法装在指定的音频文件。
  2. 调用mediaPlayer对象的prepare()方法准备音频。
  3. 调用MediaPlayer对象的start() pause() stop()方法控制播放即可。

播放来自网络的音频文件

有两种方式:

  1. 直接使用MediaPlayer对象的静态create()方法。
  2. 调用MediaPlayer对象的setDataSource()方法装载指定的Uri对应的音频文件。

使用第二种方法播放来自网络的音频文件的步骤如下:

  1. 根据网络上的音频文件所在的位置创建Uri对象
  2. 创建mediaplayer对象,并调用MediaPlayer对象的setDataSource()方法装载uri对应的音频文件。
  3. 调用MediaPlayer对象的prepare()方法准备音频。
  4. 调用MediaPlayer对象的start() pause() stop()方法控制播放即可。

注意:mediaPlayer对象除了可以使用prepare()方法来准备声音之外,还可以使用prepareAsync()方法来准备声音。

两种方法的区别在于:prepareAsync()方法是异步的,不会阻塞当前的UI线程。

播放带数字版权保护(DRP)的媒体文件

Android 8 对MediaPlayer的功能进行了增强-从android 8 开始,mediaPlayer提供了方法来支持播放带有数字版权保护的媒体文件。MediaPlayer并没有提供MediaDrm的全部功能,但对大部分通用场景,MediaPlayer的功能已经足够。

mediaplayer支持处理以下内容类型

Widvine保护的本地媒体文件

Widvine保护的远程媒体文件

为了处理有数字版权保护的媒体文件,mediaPlayer对象在执行了prepare()方法之后调用getDrmInfo()方法来获得该媒体文件的数字版权保护信息,如果该方法返回的数字版权信息不是null,那么说明该文件存在数字版权保护,接下来程序就需要处理媒体文件的数字版权信息了。

使用mediapLayer对象的prepaerDrm()

使用MediaPlayer对象的getKeyRequest()方法

使用player对象的provideKeyResponse()方法

如果需要使用异步的方式来处理数字版权信息,MediaPlayer对象提供了setOnDrmListener()方法,为该方法传入的Mediaplayer.OnDrmInfoListener参数负责监听该媒体文件的数字版权信息。

Android 9 对mediaplayer进行了增强,内置了HDR VP9 视频的本地解码器,所以开发者可以直接使用Android本地解码器来播放HDR视频。

11.1.2 音乐特效控制

android可以控制播放音乐时的均衡器 重低音 音场 显示音乐波形等。

这些都是需要AudioEffect及其子类来完成的。

其包含的常用子类如下:

AcousticEchoCanceler:取消回声控制器

AutomaticGainControl:自动增益控制器。

NoiseSuppressor:噪音压制控制器

BassBoost:重低音控制器

Equalizer:均衡控制器

PresetReverb:预设音场控制器

Visualizer:示波器

上述的子类中前三个子类用法简单,只需要调用其中的create()方法创建相应的实例,然后调用他们的isAvailable()方法判断是否可用即可。再调用setEnabled(boolean enabled)方法启用相应效果即可。

后边四个类都需要调用构造器来创建实例,创建实例时,需要传入一个audioSession参数,为了启用他们,同样需要调用AudioEffect基类的setEnabled()方法。

获取BassBoost对象之后,调用它的setStrength(shot strength)方法来设置重低音的强度。

获取PresetReverb对象之后,可调用它的setPreset()方法设置使用预设置的音场。

Equalizer对象提供了getNumberOfPresets()方法获得系统所有预设的音场,并提供了getPresetName()方法获得预设音场的名称。

实例:音乐的示波器 均衡 重低音 和音场

//

使用上述子类的时候需要用到RECORD_AUDIO权限,因此需要设置权限。

在使用Visualizer对象绘制波形图的时候,这里创建了一个内部类View,用来将Visualizer对象传过来的数据动态绘制波形效果。

11.1.3 使用VolumeShaper控制声音效果

Android 8 新增了VolumnShaper对象来控制声音效果,VolumnShaper对象可以实现音量的淡入,淡出等自动音量转换效果。

使用该对象进行音量控制实际上是使用VolumnShapaer.Configuration来实现的,创建该对象时,主要通过三个方法来指定三个参数。

持续时间:duration,指定该声音效果的持续时间,以毫秒为单位。

插值方式:interpolator type:指定声音变化的插值方式。

音量曲线:volumn curve:指定音量变化的曲线。该参数需要两个长度相同的数组,第一个数组表示各时间点,第二个数组表示个时间点对应的音量。

这些数组的值必须在0-1f之间。

在创建了VolumnShaper.Configuration对象之后,调用支持VolumnShaper的声音播放器(如mediaplayer audioTrack等)的createVolumnShaper()方法创建VolumnShaper即可。

在使用声音播放器创建了VolumnShaper之后,必须调用VolumnShaper的play()方法,否则,只有第一个音量控制点指定的音量会作用于该声音效果。

综上所述,使用VolumnShaper控制声音效果的步骤如下:

  1. 创建VolumnShpaer.Confifuration对象,在创建该对象时需要指定持续时间 音量曲线,插值方式三个参数。
  2. 调用声音播放器的createVolumnShaper()方法创建VolumnShaper对象。
  3. 调用VolumnShaper对象的play()方法。

11.1.4 使用SoundPool播放音效

可以管理短促的音效

可以在开始时加载多个音效,然后使用id来控制不同的音效来进行播放。

Android系统SoundPool提供了一个Builder内部类,该内部类专门用于创建SoundPool。

创建该对象之后,就可以使用该对象的四个load()方法来加载声音了。

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

Int load(FileDescriptor fd,long offest,long length,int priority):加载fd对应的文件中从offset开始长度为length的声音。

使用SoundPool播放指定声音的方法如下:

注意:

使用SoundPool播放声音的步骤如下:

实例:
创建SoundPool对象的代码:

重点注意:

11.1.5 使用VideoView播放视频

该组件位于android.widget包下的组件

使用VideoView组件加载指定视频的方法:

  1. 在界面布局中定义一个VideoView组件,或在程序中创建VideoView组件。
  2. 调用VideoView组件的两个方法来加载指定音频:

setVideoPath(String path)加载path文件所代表的视频

setVideoURI(Uri uri)方法加载uri所对应的视频。

  1. 调用videoView的start() stop() pause()方法来控制视频的播放。

实际上,与VideoView结合使用的还有一个MediaController类,作用是提供一个友好的图形界面,可以通过该界面实现对视频的播放控制。

重要代码实例:

当视频文件存在时:

注意:

11.1.6 使用MediaPlayer和SurfaceView播放视频

使用上述两种对象播放视频的步骤如下:

  1. 创建MediaPlayer对象,并让它加载指定的视频文件。
  2. 在界面布局文件中定义SurfaceView组件,或在程序中创建SurfaceView组件,并为SurfaceView的SurfaceHolder添加Callbac监听器。
  3. 调用MediaPlayer对象的setDisplay(SurfaceHolder sh)方法将所播放的视频图像输出到指定的surfaceView组件。
  4. 调用MediaPlayer对象的start() stop() pause()方法控制视频的播放。

注意:由于程序需要使用SurfaceView来显示MediaPlayer的图像输出,所以需要使用一些代码来维护SurfaceView,SurfaceHolder对象。

代码如下:

11.2 使用MediaRecorder录制音频

步骤:

  1. 创建MediaRecorder对象
  2. 调用MediaRecorder对象的setAudiosource()方法设置声音来源,一般传入MediaRecorder.AudioSource.MIC参数指定来自麦克风的声音。
  3. 调用MediaRecorder对象的setOutputFormat()方法设置录制的音频格式文件。
  4. 调用MediaRecorder对象的setAudioEncoder()方法,setAudtioEncodingBitRate(int bitRate)、setAudioSamplingRate(int sampliingRate)方法设置所录制的声音编码格式,编码位率,采样率等。这些参数可以控制所录制声音品质,文件大小。
  5. 调用该对象的setOutputFIle(String path)方法设置录制的音频文件的保存位置。
  6. 调用MediaRecorder对象的prepare()方法准备录制。
  7. 调用MediaPlayer对象的start()方法开始录制。
  8. 录制完成,调用MediaRecorder对象的stop()方法停止录制,并调用release()方法释放资源。

核心代码:

需要增加的权限:

重点:

11.3 控制摄像头拍照

11.3.1 Android 9 改进的Camera v2

使用Camera v2 API来控制摄像头拍照的步骤:

//实例:拍照时自动对焦

获得摄像头信息的代码:

通过stateCallback中的onOpened()方法的参数可以获得被打开的摄像头设备。

此外,在onOpened()方法中调用createCameraPreviewSession()方法创建了CameraCaptureSession,并开始预览取景。

重点注意:

11.3.2 录制视频短片

步骤:

  1. 调用MediaRecorder对象的setVideoEncoder().setVideoEncodingBitRate(),setVideoFrameRate()方法设置所录制的视频编码格式,编码位率,每秒多少帧等。
  2. 调用MediaRecorder对象的setPreviewDisplay()方法设置使用哪一个SurfaceView组件来显示视频预览。

其他代码和录制音频的一样。

//实例:录制生活短片

重要代码:

需要增加的权限:

录制声音的权限

使用摄像头的权限

使用外部存储器的权限

11.4 屏幕捕捉

使用android提供的MediaPlayerManager管理器。

步骤如下:

核心代码:

11.5 本章小结

  1. OpenGL 与3D开发

OpenGL本身是高效、简洁的开放图形库接口。

定义了一个跨编程语言、跨平台的编程接口规范。

12.1 3D图形和3D开发基本知识

绘制3D图形需要用到的数据:

12.2 OpenGL 和 OpenGL ES简介

OpenGL具有更广泛的适应性。

OpenGL ES 是 OpenGL的一个子集。

12.3 绘制2D图形

12.3.1 在android中使用OpenGL ES

Android中支持提供了GLSurfaceView组件,该组件用于显示3D图形。

GLSurfaceView本身不提供绘制3D图形,而是由GLSurfaceView.Renderer来完成SurfaceView中3D图形的绘制。

步骤:

  1. 创建GLSurfaceView组件,使用activity来显示该组件。
  2. 为GLSurfaceView组件创建一个GLSurfaceView.Renderer实例,实现GLSurfaceView.Renderer类时选哟实现该接口中的三个方法。

Abstract void onDrawFrame(GL10 gl):Renderer对象调用该方法绘制GLSurfaceView的当前帧。

Abstract void onSurfaceChanged(GL10 gl,int width,int height):当GLSurfaceView的大小改变时回调该方法。

Abstract void onSurfaceViewCreated(Gl10 gl,EGLConfig config):当GLSurfaceView被创建的时候回调该方法。

  1. 调用GLSurfaceView组件的setRenderer()方法指定Renderer对象,该Renderer对象将会完成GLSurfaceView里面的3D图形的绘制。

绘制3D图形的难点是:如何设置Renderer类。

当SurfaceView被创建时,系统会回调Renderer对象的onSurfaceCreated()方法,该方法可以对OpenGL ES执行一些无需任何改变的初始化,初始化代码如下:

GL10 就是OpenGL ES 的绘图接口。

关于上述代码中的方法说明如下:

在onSurfaceChanged()方法中用于初始化3D场景的代码是:

一些说明:

GLSurfaceView上的所有3D图形都是由Renderer的onDrawFrame(GL10 gl)方法绘制出来的,重写该方法的时候就要把所有的3D图形都绘制出来。

然后下面就可以调用gl10对象的方法开始绘制了。

12.3.2 绘制平面上的多边形

绘制3D图形就是通过多个平面图形形成的。

绘制2D图形如下:

  1. 调用GL10 的glEnableClientState()方法启用顶点坐标数组
  2. 调用GL10 的glEnableClientState()方法启用顶点颜色数组。
  3. 调用GL10的glVertexPointer()方法设置顶点的位置数据。

上述第三个方法中的参数pointer参数用于指定顶点坐标值。是一个三维数组。

第一个参数size指定多少个pointer数组中的元素成为一个顶点位置。通常为3。

type参数指定顶点坐标值的类型。

  1. 调用GL10的glColorPointer()方法设置顶点的颜色数据。

第4个方法中pointer参数指定顶点的颜色值,也是一个一维数组。

其中的size通常设置为4,表示指定pointer数组中每4个元素作为一个顶点坐标值。

  1. 调用GL10 的glDrawArrays()方法绘制平面。该方法的第一个参数指定绘制图形的类型,第二个参数指定从哪个顶点开始绘制,第三个参数指定总共绘制的顶点数量。
  2. 绘制完成后,调用GL10 的glFinish()方法结束绘制,并调用glDisableClientSate(int)方法来停用顶点坐标数据,顶点颜色数据。

//实例

代码:

在onDrawFrame()方法中绘制图形:

其中,使用glTranslatef()方法目的是将图形的绘制保证在中心点上。

在onCreate()方法中使用如下代码即可实现绘制:

可以借助maya或3dMAX将顶点坐标数据导入到程序中实现绘制。

12.3.3 旋转

GL10提供了使用glRotatef()方法用于控制旋转。

该方法中的angle控制旋转角度,x,y,z参数则共同决定了旋转轴的方向。

实现不断旋转的特效只需要将旋转的角度增加即可。

只需要在onDrawFrame()方法最后添加:rotate+= 1;即可。

12.4 绘制3D图形

定义的顶点不在同一个平面上,并使用三角形将合适的顶点连接起来,就可以绘制出来一个3D图形了。

12.4.1 构建3D图形

GL10 提供了glDrawElements()方法,参数为:int mode,int count,int type,Buffer indices。根据indices指定的索引点来绘制三角形。

该方法的第一个参数指定绘制的图形类型,第二个参数指定一共包含多少个顶点,第三个参数最重要:其包装了一个长度为3N的数组,其中三个元素表示一个顶点。

3D图形的绘制需要在程序中指定每一个面由哪三个顶点组成。

12.4.2 应用纹理贴图

在Renderer实现类中的onSurfaceCreated()方法中启用纹理贴图。代码如下:

准备的图片的规格需要是:长,宽是2的N次方。

加载图片生成贴图的代码如下:

说明:

  1. glGenTextures(int n ,int[] textures,int offsets)该方法指定一次性生成n个纹理。

该方法所生成的纹理代号放入其中的testures数组中,offsets指定从第几个数组元素开始放置纹理代号。

  1. glBindTexture(int target,int texture),该方法用于将texture纹理绑定到target目标上。
  2. GlTextParameterf(int target,int pname,float param),该方法用于为target纹理目标设置属性,其中第一个参数是属性名,第二个参数是:属性值。

在3D绘制中设置纹理贴图:

  1. 设置启用贴图的坐标数组。
  2. 设置贴图坐标的数组信息。
  3. 调用GL10的glBindTexture(int target,int texture)方法执行贴图。

12.5 本章小结

第13章 android网络应用

android支持JDK自带的网络编程。

由于android删除了Apache HttpClient支持,有一个OkHttp框架的支持。可以取代原来的Apache HttpClietn支持。

13.1 基于TCP协议的网络通信

13.1.1 TCP协议基础

//略

13.1.2 使用ServeSocket创建TCP服务器端

可以接受其他实体连接请求的类是ServerSocket。

该对象包含的方法:

  1. Socket accept()方法接受一个客户端Socket的连接请求。该方法将返回一个与连接客户端Socket对应的Socket。否则,盖方法将一直处于等待状态,线程被阻塞。
  2. ServerSocket(int port)用指定的端口port来创建一个ServerSocket对象。
  3. ServerSocket(int port,int backlog)增加了一个用来改变连接队列长度的参数backlog。
  4. ServerSocket(int port,int backlog,InetAddress localAddr)。在机器存在多个ip地址的情况下,允许通过localAddr这个参数来指定将ServerSocket绑定到指定的ip地址。

通常使用循环控制不断调用ServerSocket的accept()方法。

代码实例如下:

当未指定I地址的时候,ServerSocket会绑定到指定的本机默认IP地址。

推荐使用1024以上的端口号作为接收的端口号。

13.1.3 使用Socket进行通信

连接到服务器端时的客户端的socket的创建:

一旦服务器和客户端连接之后,就不需要在分服务器和客户端了。因为两者都可以发送和接受消息进行交互。

其中Socket提供了两个方法来实现消息的交互:

  1. InputStream getInputStream()方法,返回该Socket对象对应的输入流,让程序通过该输入流从Socket中得到数据。
  2. OutputStream getOutputStream()方法,返回该Socket对象对应的输出流,让程序通过该输出流向Socket中输出数据。

服务器端代码实例:

客户端代码实例:

注意:直接在UI线程中建立连接,是不合适的,会阻塞线程。

使用Socket对象的setSoTimeout(int timeout)方法来设置超时时长。

使用下述代码可以实现创建以恶搞Socket对象来直接在链接的时候设置超时时长:

13.1.4 加入多线程

服务器应当给每一个Socket单独启动一个线程。每个线程负责与一个客户端进行通信。

可以使用List保存所有的Socket对象。

代码:

其中的另外一个线程代码:

在run()方法中设置:

上述代码实际上实现了群发消息的功能。

每个客户端包含两个线程:

  1. 一个包含UI界面的创建
  2. 一个是包含和服务器端的数据交互。

为了避免UI线程阻塞,程序将建立网络连接,与网络服务器通信等工作都交给ClientThread线程完成。

使用handler主要是为了实现子线程和UI界面进行数据交互。

13.2 使用URL访问网络资源

URL是指向互联网资源的指针。

URL的格式:

URL包含一个可以打开到资源的输入流。

URI的实例代表一个统一资源标识符,java中的URL不可以用来定位任何资源,唯一作用是解析。

URL对象的方法:

13.2.1 Android 9 安全性增强的URL

由于从Android 9 网络连接默认是加密的,那么如果访问的服务器是http的就需要在配置文件中加上:

第一种方式实例:

13.2.2 使用URLConnection对象提交请求:

URL的openConnection()方法创建URLConnection对象,程序可以使用该对象向URL请求获得资源。

创建一个URL的连接的步骤:

  1. 调用URL对象的openConnection()方法创建URLConnection对象。
  2. 设置URLConnection的参数和普通请求属性。
  3. 如果是GET请求,那么使用connect方法建立和远程资源之间的实际连接即可。
  4. 如果是post请求,那么需要获得URLConnection对象对应的输出流来发送请求参数。
  5. 远程资源变为可用,程序可以访问远程资源的头字段或通过输入流得到远程资源的数据。

在建立和远程资源的实际连接之前,程序通过如下方法设置请求头字段:

注意:一定要先使用输入流然后再使用输出流。

JDK提供的访问特定响应头字段的值:

注意:发送post请求必须获得如下两行:

发送post请求:

13.3 使用HTTP访问网络:

13.3.1 使用HTTPURLConnection对象

该对象继承了URLConnection,也可以放松GET和POST请求。

该对象提供了如下便捷的方法:

//实例:多线程下载:

实现步骤:

  1. 创建URL对象
  2. 获得指定URL对象所指向资源的大小(由getContentLength()方法实现),此处用到了HTTPURLConnection类。
  3. 在本地磁盘上创建一个与网络资源相同大小的空文件。
  4. 计算每条线程应该下载的网络资源的那个部分。
  5. 依次创建,启动多条线程来下载网络资源的指定部分。

代码中需要使用:inputStream的skip()方法跳过指定数量的字节。

13.3.2 使用OKHttp

如果只是向一个页面提交请求并获得服务器的响应,则完全可以使用前面所介绍的HttpURLConnetion来完成。

为了处理WEB站点包含的Session Cookie等,使用OKHttp实现。

使用步骤:

//实例:访问被保护的资源

(使用OKHttp来访问被保护的页面)

需要使用OKHttpClient对象实现登录网页。

只要应用程序使用同一个OKHttpClient对象发送请求,并让该对象管理Cookies,那么该对象就会自动维护和服务器之间的session状态。

OKHTTPClient有自己的线程池和连接池,可以进行复用。

为了在android中使用OKHTTP,首先需要下载OKHttp的两个jar包。(Okio)。

也可以使用Gradle下载:

这里总结一下实现网络通信的时候app端的activity常用代码块:

1.需要设置一个MyHandler类继承自Handler类,主要是为了获得线程传来的数据更新UI界面。

2.需要在onCreate()方法中初始化各种对象,然后添加一个requestPermission()来获得用户权限。

3.在Activity类内部创建一个线程类,主要是为了在和服务器端交互数据的时候不阻塞UI线程。

4.在使用了OKHttp框架的onCreate()方法内部,创建默认的该对象:

  1. 使用对应的call对象发送同步或异步请求。
  2. 然后,设置message对象,发送到前边

    以上是关于Android高级终端开发学习笔记(《疯狂Android讲义》第11章-第17章)的主要内容,如果未能解决你的问题,请参考以下文章

    Android学习笔记

    干货Android中高级开发进阶必备资料(附:PDF+视频+源码笔记)

    安卓学习课程

    Android八大模块进阶学习笔记(性能优化百大框架高级UIFlutterKotlin...)

    Android进阶全套学习笔记开源,三个月学完,入职谷歌高级开发部

    看懂Android学习最佳路线