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对象,发送到前边的Handler接受对象中,用来更新UI线程。
  3. 在创建对话框的方法中有如下代码:

为了创建一个可以输入用户名和密码的对话框。

上述的FromBody对象用来封装请求的参数。

  1. 登录成功之后OKHTTPCLIENT对象会自动维护和服务器之间的连接。并维护和服务器之间的session状态。

13.4 使用WebView组件进行混合开发

一种混合的开发方式:

Android + HTML 5混合开发

13.4.1 使用WebView浏览网页

//实例:迷你浏览器

13.4.2 使用WebView加载HTML代码

使用该对象的loadData()方法或者loadDataWithBaseURL()方法

后者中的参数:

13.4.3 使用webView中的javaScript调用Android方法

使用WebSettings工具类,该工具类提供了大量方法来管理WebView组件的选项设置。

其中的setJavaScriptEnabled(true)方法即可让WebView组件中的javaScript脚本调用Android中的方法。

为了将android对象暴漏给WebView中的js代码,WebView还提供了addJavascriptInterface(Object object,String name)方法。该方法负责将object对象暴漏给js中的name对象。

步骤:

  1. 调用webView关联的WebSettings的setJavaScriptEnabled(true)启动Js调用功能。
  2. 调用webView组件的addJavascriptInterface()方法将object对象暴漏给js脚本。
  3. 在Js脚本中通过刚才暴漏的name对象调用android方法。

在android将暴漏对象中的方法上添加上注释:@JavascriptInterface即表示:将该类中的该方法提供给了webView组件加载的html界面中的js代码。

在WebView组件中的代码如下:

13.5 本章小结

第14章 管理Android系统桌面

14.1 改变壁纸

使用WallpaperManager对象来改变壁纸,在该对象中改变壁纸的方法如下:

14.1.1 开发动态壁纸

开发动态壁纸的步骤如下:

  1. 开发一个子类继承自WallpaperService基类。
  2. 继承WallpaperService基类时必须重写onCreateEngine()方法,该方法将返回WallpaperService.Engine子类对象。
  3. 开发者需要实现WallpaperService.Engine子类,并重写其中的onVisibilityChanged(),onOffsetsChanged()方法。

(还可以有选择性地重写SurfaceHolder.Callback中的三个方法)

//14.1.2 实例:动态壁纸

还需要在配置文件中进行配置:

需要指定:

详细的配置实例:

才算完成了配置。

14.2 快捷方式

Android 8 提供了Pinned快捷方式替代原有的桌面快捷方式。

还提供了一个管理类ShortcutManager管理类。

Android中提供的添加快捷方式的方法:

  1. 静态方式:只需要通过配置文件即可添加快捷方式。
  2. 动态方式:通过ShortcutManager对象可为应用程序动态添加、删除、更新快捷方式。
  3. 桌面快捷方式:需要通过ShortcutManager对象进行动态添加。

14.2 静态快捷方式

步骤:

  1. 在主Activity中添加name为android.app.shortcuts的元素,该元素指定静态快捷方式的配置文件。
  2. 为静态快捷方式添加配置文件。

实例代码:

然后在/res/xml文件下创建一个xml文件:

对上述快捷方式配置的解释说明:

其中的子元素对应的启动的activity通过子元素指定。

android要求必须为 元素指定action属性。

14.2.2 动态快捷方式

方法如下:

  1. 添加快捷方式:使用setDynamicShortcuts()或addDynamicShortcuts()方法来添加快捷方式。
  2. 更新快捷方式:使用updateShortcuts()方法来更新快捷方式。
  3. 删除快捷方式:使用removeDynamicShortcuts()方法删除指定的快捷方式,或者使用removeAllDynamicShortcuts()方法删除所有的快捷方式。

14.2.4 桌面快捷方式(Pinned Shortcut)

//实例:让程序占领桌面

其中的button组件的点击事件为:

上述代码中的2中的Null参数位置表示可以设置当该桌面快捷方式创建成功的时候的回调方法。

14.3 管理桌面控件

14.3.1 开发桌面控件

桌面控件通过BroadcaseReceiver的形式来进行控制的。每一个桌面控件对应一个BroadcastReceiver。

为了简化桌面控件的开发,android系统提供了一个AppWidgetProvider类。

该类是AppWidgetProvider的子类。该类的生命周期方法(有四个):

步骤如下:

  1. 在provider类中创建一个RemoteViews对象,创建该对象时可以指定加载指定的界面布局文件。
  2. 如果需要改变上一步所需要加载的界面布局文件的内容,则可以通过RemoteViews对象进行修改。

一般来说,RemoteViews组件所加载的界面中主要包含了ImageView和TextView组件两个组件。

  1. 创建一个ComponentName对象。
  2. 调用AppWidgetManeger更新桌面控件。

具体代码实例:

由于AppWidgetProvider对象继承了BroadcastReceiver类,所以需要在配置文件中配置它。

需要指定: 和

具体代码实例:

此外还需要在/res/xml文件下设置一个appwidget_provider.xml文件:

文件的内容如下:

其中使用了 元素来描述桌面控件的基本信息。

使用桌面控件开发者可以将应用程序的运行界面直接放到桌面上。

//实例:液晶时钟

核心代码:

使用循环实现对数据的更新。

然后在配置文件中进行配置:

其中的resource的文件对应的详细内容和

大致一样。

14.3.2 显示带数据集的桌面控件(重点)

android为RemoteViews提供了如下的方法:

setRemoteAdapter()方法:该方法可以使用intent更新RemoteViews中ViewId对应的组件。

上面的方法的Intent参数应该封装一个RemoteViewsService参数。该参数虽然继承了Service组件,但是主要作用是为RemoteViews中viewId对应的组件提供列表项。

实例代码:

其中的RemoteViews xxx()方法返回的是一个RemoteViews对象。

提供了StackWidgetService之后,接下来开发AppWidgetProvider子类与开发普通AppWidgetProvider子类的步骤基本相同,此时调用的是:setRemoteAdapter(int viewId,Intent intent)方法。

其中,在provider实现类的onUpdate()方法中的代码为:

上述实例文件中的代码如下:

该实例同样需要在res/xml目录下添加一个元数据配置文件(主要是为了配置控件的显示等)。

14.4 本章小结

第15章 传感器应用开发

开发者只需要为传感器注册一个监听器即可。

15.1 利用android的传感器

步骤:

  1. 调用Context的getSystemService()方法获得SensorManager对象。SensorManager对象代表系统的传感器管理服务。
  2. 调用SensorManager的getDefaultSensor(int type)方法来获得指定类型的传感器。
  3. 通常选择在Activity的onResume()方法中调用SensorManager的registerListener()方法为指定传感器注册监听器。程序通过实现监听器即可获得传感器传回来的数据。

对监听器的说明:

实现简单的传感器监听事件逻辑:

  1. 使MainActivity实现SensorEventListener接口。
  2. 在其中onCreate()方法中获得传感器服务。
  3. 在onResume()方法中为系统的加速度传感器注册监听器。
  4. 在onSensorChanged()方法中,得到该传感器传回来的数据,然后输出。

注意:android模拟器没有提供传感器支持。

15.2 Android的常用传感器

15.2.1 方向传感器

对于手机围绕着三个轴转动的情况说明:

15.2.2 陀螺仪传感器

用于感应手机设备的旋转速度。

旋转速度的单位是:弧度/秒,旋转速度为正值代表逆时针旋转,负值代表顺时针旋转。

返回的三个角速度说明如下:

//截止到:2021/6/20日下午12:17

//2021/6/25日下午22:41开始学习笔记

15.2.3 磁场传感器

主要用于读取手机设备外部磁场的强度。

磁场数据的单位是微特斯拉(uT)。

15.2.4 重力传感器

会返回一个三维坐标向量,这个三维向量可显示重力的方向和强度。

重力传感器的坐标系统和加速度传感器的坐标系统是相同的。

15.2.5 线性加速度传感器

返回一个三维向量显示设备在各个方向上的加速度。

加速度传感器 = 重力传感器 + 线性加速度传感器

15.2.7 光传感器

用于获得环境中的光照强度。单位是lux。

15.2.8 湿度传感器

返回一个数据表示相对环境中空气湿度百分比。

15.2.9 压力传感器

用于获得手机设备所处环境的压力大小。

15.2.10 心率传感器

可以返回佩戴该设备的人每分钟的心跳次数。

15.2.11 离身传感器

用于感知设别的佩戴状态。适合处理手表等可穿戴设备。

使用获得系统服务的代码得到传感器管理对象:

为不同的传感器设置监听器:

在onSensorChanged()方法中代码:

获得触发的传感器类型:

//15.3 传感器应用实例

实例:指南针

//实例:水平仪

代码实现思路:

  1. 设置一个MyView类创建位图:获得窗口管理器,获得屏幕的宽度和高度,创建位图,设置绘制风格,创建一个线性渐变来绘制线性渐变,绘制圆形,设置绘制风格,绘制圆形边框,绘制水平横线,绘制垂直横线,设置画笔颜色,绘制中心的一个十字,加载气泡图片。
  2. 在MyView类中的onDraw()函数中根据气泡坐标绘制气泡。
  3. 在MainActivity中定义水平仪的仪表盘,定义Sensor管理器,在onCreate()函数中获得水平仪的组件,获得传感器管理服务,在onResume()函数中为系统的方向传感器注册一个监听器。
  4. 在onPause()函数中,设置取消注册。
  5. 在onSensorChanged()函数中获得触发的传感器类型,使用case判断获得传感器的类型,获得对应的夹角等信息,设置气泡的位置。
  6. 使用设置的isContain()函数判断更新后的气泡坐标是否还在水平仪的仪表盘内。

//15.4 本章小结

//截止到:2021/6/25 23:15截至

//2021/6/26日上午9:07开始学习笔记

  1. GPS 应用开发

android为支持GPS提供了LocationManager类。

16.1 支持GPS的核心API

使用getSystemService()函数获得manager类。

提供的方法有:

addGPSStatusListener()函数添加一个监听GPS状态的监听器。

addProximity()函数添加一个临近警告。

List getAllProvider()函数获得所有的LocationProvider列表。

String getBestProvider()函数:根据指定条件返回最优的LocationManager对象。

GpsStatus getGpsStatus()函数获得GPS状态。

Location getLastKnownLocation()根据provider(函数中的参数)获得最近一次已知的Location。

LocationProvider getProvider()函数:根据名称获得LocationProvider对象。

List getProvider():获得所有可用的LocationProvider对象。

Boolean isProviderEnabled()函数:判断指定名称的LocationProvider是否可用。

removeGpsStatusListener()函数:删除Gps状态监听器。

RemoveProximityAlert()函数:删除一个临近警告。

requestLocationUpdates()函数:通过指定的LocationProvider周期性地获得定位信息,通过intent启动相应的组件。

requestLocationUpdates()函数通过指定的LocationProvider对象周期性地获得定位信息。触发Listener对象的触发器。

LocationProvider对象是重要的定位提供者。通过该对象可以获得相关组件的定位信息。

其中的常用方法是:

GPS定位支持还有一个API:Location,是一个代表位置信息的抽象类。提供了如下方法来获得定位信息。

使用上述三个组件对象获得定位信息的步骤如下:

  1. 获得系统的LocationManager对象。
  2. 使用LocationManager对象通过指定LocationProvider对象来获得定位信息,定位信息由Location对象来表示。
  3. 从Location对象中获得定位信息。

16.2 获得LocationProvider对象

16.2.1 获得所有可用的LocationProvider对象

提供了一个getAllProviders()方法来获得系统所有可用的LocationProvider对象。

注意:如果使用真机,那么会出现一个network的LocationProvider对象,表示通过移动网络获得定位信息的LocationProvider对象。

16.2.2 通过名称获得指定LocationProvider对象

程序调用LocationManager对象的getAllProviders()函数获得所有的LocationProvider对象。

16.3 获得定位信息

在获得了LocationManager对象之后,就可以通过指定的LocationProvider对象来获得定位信息了。

16.3.1 通过模拟器发送GPS信息

android模拟器本身并不能 作为GPS接收机,因此无法得到GPS的定位信息。

16.3.2 获得定位数据

需要在清单文件中增加对应的权限。

16.3.3 Android新增的室内WI-FI定位

Android 9 新增了队RTT WI-FI协议的支持

可以使用设备测量与多个WIFI接入点的距离,可以使用定位算法来对改设备进行定位。

室内WIFI定位管理器对象是:WifiRttManager。

获得了该对象之后,程序调用startRanging()函数开始定位:

使用室内WIFI定位步骤:

  1. 获得WifiRttManager对象。
  2. 通过RangiingRequest.Builder创建RangingRequest对象,在创建该对象之前先添加WIFI扫描得到的WIFI访问点信息。
  3. 调用WifiRttManager对象的startRanging()方法开始定位,通过传给该方法的第三个参数RangingResultCallback对象来获得室内定位信息。

注意:只有当版本大于Android 9 时才可以使用WIFI定位功能。

实例步骤:

  1. 定义一个监听WIFI状态改变的BroadcastReceiver类,用来接受消息的时候开始定位。
  2. 在onCreate()方法中定义一个监听网络状态改变,WIFI状态改变的IntentFilter对象
  3. 为该intentFilter对象注册上述的BroadcastReceiver对象。
  4. 设置执行WIFI定位的方法。
  5. 该方法中:获得wifi管理器,判断是否支持室内WIFI定位功能,获得室内WIFI定位管理器,添加WIFI扫描的结果(结果由WIFI管理器使用getScanResults生成),创建RangingRequest对象。
  6. 然后,使用室内WIFI定位管理器的startRanging()方法来执行室内WIFI定位。
  7. 在方法内部的第三个参数中的onRangingResults()方法中使用for循环遍历得到的结果从而实现获得可接入的特定的WIFI之间的距离。

16.4 临近警告

需要说明的是:addProsimityAlert()方法中,如果设备只是简单地通过被检测区域,系统可能不会激发Intent,需要在真机上运行。

16.5 本章小结

  1. 整合高德Map服务

17.1 调用高德Map服务

17.1.1 获得Map API key

步骤如下:

  1. 首先找到该App的数字证书的KeyStore的存储路径。
  2. 为了获得第三方的Map服务的API Key,需要先用JDK提供的keytool查看keystore的认证指纹。启动命令窗口,输入命令。

注意:

  1. SHAI的认证指纹,然后登录高德地图的网站。
  2. 获得账号。
  3. 激活邮箱。
  4. 申请Key。
  1. 首先单击该页面上的:“创建新应用”,然后单击添加新Key按钮。
  2. 在文本框输入keytool工具查看到SHAI指纹,单击提交按钮。

17.1.2 高德地图入门

高德地图提供了一个MapView组件,该组件继承了FrameLayour组件,本质上就是一个普通的容器组件。

MapView组件是一个容器,真正地MapView提供地图支持的是AMap类。MapView可以通过getMap()方法来获得所封装的AMap对象,AMap提供了大量的方法来控制地图。

建立的包名和申请的时候设置的需要保持一致。

需要添加高德地图的SDK:

登录官网,下载SDK包,将解压缩之后的jar包制到app/libs目录下。在app/src/mani目录下新建一个jniLibs子目录。然后将arm64-v8a,armeabi,armeabi-v7a,x86,x86_64这5个文件夹复制到该目录下。

打开清单文件,在该文件中的application元素中添加如下:meta-data子元素:

在清单文件中添加权限文件:

注意:

MapView组件需要在Activity的生命周期中回调该MapView组件的生命周期方法。

17.2 根据GPS信息在地图上定位

AMap提供如下的方法来控制地图:

然后设置监听地图,用于响应用户操作:

步骤:

  1. 创建一个Xxxoptions。
  2. 调用XxxOptions的各种setter方法来设置属性。
  3. 调用AMap对象的addXxx()方法添加即可。

为了表示Map上的指定点,高德地图还提供了LatLng类。该类就是对经纬度的封装。

还提供了一个CameraUpdate类,该类需要通过CameraUpdateFactory来创建该类的实例。

CameraUpdate可控制地图的缩放级别、定位、倾斜角度等信息。

程序调用AMap对象的moveCamera()方法根据CameraUpdate对地图进行缩放等操作。

根据经纬度在AMap上定位的步骤:

  1. 根据程序获得的经纬度创建LatLng对象。
  2. 调用CameraUpdateFactory的changeLatLng()方法创建改变地图中心的Camera对象。
  3. 调用AMap的moveCamera()方法即可控制地图定位到指定位置。

17.3 实际定位

17.3.1 地址解析和反向地址解析

地址解析:将用户输入的字符串地址转换成为精度和纬度

方向地址解析:将精度和纬度转换成普通的字符串。

高德地图提供了GeocodeSearch工具类,该工具类提供如下方法:

实际上该类需要调用网络上的高德地图服务。

上述的两种地址解析使用异步交互的方法进行。

步骤:

  1. 创建GeocodeSearch对象,并为该对象设置解析监听器。
  2. 如果要进行地址解析,程序先创建GeocodeQuery对象,该对象封装了要解析的地理名称、城市等信息。如果要进行反向地址解析,程序先创建LatLngPoint对象,该对象封装了经度、维度信息。
  3. 调用GeocodeSearch对象的方法执行地址解析或反向地址解析。

17.3.2 根据地址执行定位

17.4 GPS导航

高德地图提供了RouteSearch查询类。专门用于查询各种路线:

使用RouteSearch获得导航路线只需要如下3步:

//截止到2021/6/26日 上午11:28

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

  1. Android高级终端开发学习笔记(《疯狂Android讲义》第2章-第10章)

    Android疯狂讲义前10章知识点总结 /-------------------------10-31号晚上学习笔记----------------------------/ 在设置了最小支持版本为 ...

  2. Android开发学习笔记---搭建Android开发环境

    今天突发奇想,想看看Android开发是什么样的,于是就在度娘了一下Android开发,便自己动手搭建了起来.中间也碰到了一些问题,自己慢慢度娘,谷哥去解决.现在把搭建步骤记录如下: 第一步:下载Ec ...

  3. 柠檬ban软件测试之python高级测试开发学习笔记

    本项目已开源数组(1174536086)←v是有序的元素序列.用于差异数组的各个元素的数字编号称为下标.若将有限个类型相同的变量的集结命名,那么这个名称为数组名.数组是一个固定长度的存储相同数据类型的 ...

  4. Android深度探索(卷1)HAL与驱动开发学习笔记(8)

    Android深度探索(卷1)HAL与驱动开发学习笔记(8) 第八章 蜂鸣器驱动   L i n u x驱动的代码重用有很多种方法.可以采用标准C程序的方式.将要重用的代码放在其他的文件(在头文件中声 ...

  5. Android 开发学习笔记

    Android 开发学习笔记 Lesson1 (2.28) android之父: Andy Rubin(安迪 鲁宾) Lesson2 (3.3) android 的优点: 开放.网络接入自由.丰富的硬 ...

  6. Android(java)学习笔记176: 远程服务的应用场景(移动支付案例)

    一. 移动支付:       用户需要在移动终端提交账号.密码以及金额等数据 到 远端服务器.然后远端服务器匹配这些信息,进行逻辑判断,进而完成交易,返回交易成功或失败的信息给移动终端.用户提交账号. ...

  7. Android学习笔记:Android基础知识点(不断更新中)

    1.Android学习笔记:OkHttp 2.Android学习笔记:更新UI的方法(UI线程和非UI线程) 3.Android学习笔记:Volley 4.Android学习笔记:Handler 5. ...

  8. Android移动应用开发教程笔记①

    本文为第一篇,主要为Android的简介和Android studio的安装以及第一个安卓程序"hello world"的创建! 本文是对B站教程 动脑学院 Android教程 学 ...

  9. Android折叠屏开发学习(三)---使用MotionLayout实现折叠屏分屏效果

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为6259字,预计阅读11分钟 前言 今天是折叠屏开发的第三篇,前面已经介绍了铰链的角度监听和Jetpack Window实现监听 ...

最新文章

  1. mysql出现“Incorrect key file for table”解决办法
  2. C语言ATD1SC,2020-10-13_ATD(模数转换)模块介绍
  3. numpy(2)-非齐次线性方程组求解
  4. 一文说通C#中的异步编程补遗
  5. 解读大型网站系统架构的演化
  6. leetcode 474. 一和零(dp)
  7. mysql孤立锁_SQL Server解决孤立用户浅析
  8. layui时间选择30分钟为单位_如何集中注意力,不妨试试番茄工作法 | 五色时间管理法...
  9. 我的sqa计划和测试规划
  10. 全局异常捕捉用法解析
  11. 21. Django进阶:内建用户系统
  12. 多变量微积分笔记19——直角坐标系和柱坐标系下的三重积分
  13. 鉴客 C# 抓取页面(带认证)
  14. 偏微分方程数值解的matlab程序,偏微分方程数值解法的MATLAB源码
  15. 上古计算机语言,微软开源其上古编程语言GW-BASIC
  16. 直播预告 | 猪齿鱼V1.1发布,线上新功能详解邀您参加
  17. html插入图片向下,HTML基础8--插入图片及嵌入
  18. 认知当下 原子世界的技术发展停滞了么
  19. 讯飞 AIUI 集成
  20. 3.2收缩-扩张喷管实例

热门文章

  1. Java中Stream的使用
  2. 忽视警告_企业无法忽视移动革命的6个原因
  3. 助力精准气象和海洋预测笔记
  4. python 矢量数据融合代码_在ArcGIS下基于Python的矢量数据处理方法
  5. Android常用三方框架
  6. html-based script和url-based script区别,使用方式
  7. iOS开发日记27-WebView与JS的交互
  8. Linux(CentOS)下安装NVIDIA GPU驱动
  9. py语法07-字符串的操作
  10. 图形开发——显卡学习