Android 学习笔记之SurfaceView的使用+如何实现视频播放...
学习内容:
1.掌握Surface的使用...
2.Android中如何实现视频播放...
1.SurfaceView类的使用
在Android中,一般播放音频时我们可以去使用Android提供的MediaPlayer类,但是想要播放视频仅仅依靠MediaPlayer类是远远不够的...这里还需要使用到一个SurfaceView这个组件来完成..为什么?因为像视频和SD图形等都需要迅速的更新...如果这个更新实在主线程内去完成,那么显然是不合理的,因为一个视频的播放,系统会首先确定视频的格式,然后得到视频的编码..然后对编码进行解码,得到一帧一帧的图像,最后在画布上进行迅速更新...这就是视频播放的机制...那么这个过程显然我们需要在另外一个线程内部去完成...这样主线程的其他内容,比如说其他的渲染操作,图片加载什么的,就不会导致主线程阻塞...这样我们就可以使用SurfaceView来完成...
SurfaceView继承了View类,也是属于视图的一部分...SurfaceView视图内嵌了一个专门用于绘制的Surface...其实每一个Surface都在每一个窗口的后面,我们可以通过SurfaceView类来控制哪些Surface的内容可以显示出来...其实说白了它的作用就是可以直接从内存或者是DMA硬件里获取图像数据...将这些图像数据迅速的显示出来,通过启动另外一个线程可以迅速的完成画面的更新操作,不会导致主线程阻塞...这个在游戏开发中也是起着非常重要的作用...
SurfaceView使用双缓冲机制,这个机制可以使SurfaceView同时对两张图片进行渲染操作...其实目的也是为了迅速更新图片的显示,第一个缓冲对这一帧进行解析,第二个会对下一帧进行解析...这样就可以避免在上一帧的图片显示完成后,下一帧的图片还没有进行显示的情况发生...这样就可以流畅的播放一个视频文件...
SurfaceView的实现...
首先需要一个类去继承这个类,然后实现SurfaceHolder.Callback()接口...使用这个接口的目的就是在Android中,SurfaceView的双缓冲机制是非常消耗资源的,因此Android规定,在SurfaceView可见的时候,SurfaceView会对文件进行解析并显示,当其不可见时,要直接销毁掉SurfaceView以节省资源...那么这个接口的目的就是形成这个过程...
需要重写的方法
(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//在surface的大小发生改变时激发
(2)public void surfaceCreated(SurfaceHolder holder){}
//在创建时激发,一般在这里调用画图的线程。然后画图的工作开始...
(3)public void surfaceDestroyed(SurfaceHolder holder) {}
//销毁时激发,一般在这里将画图的线程停止、释放。
这三个方法就形成了上述说的那种关系...在视频的播放当中,它会结合MediaPlayer完成视频的流畅播放..而在游戏的开发当中,它可以结合Canvas元素来完成游戏中的一些画面迅速更新的操作...
总而言之,SurfaceView就是一个绘图的容器,它可以在不干扰主线程的情况下,调用另一个线程完成绘图的操作,并迅速的更新图像...以完成更好的显示效果....
这里来两个实例...一个是SurfaceView配合MediaPlayer完成视频的播放,另一个是结合Canvas完成一个图像在画布上显示出来...
1.结合Canvas完成图像在画布上的显示...
这里做了一个摩尔斯灯塔....什么是摩尔斯灯塔...这玩意其实在以前的战争中可以使用的到,这里有一个概念就是摩尔斯码...这个码就是将数字,字母等符号以"."和"-"的形式显示出来就是对文字的一种加密操作...出了可以发报文的形式,还可以以信号灯的形式来发送密报,然后另一方根据对应的信息进行解析...扯远了...
a .- b -... c -.-. d -.. e . f ..-. g --. h .... i .. j .--- k -.- l .-.. m -- n -. o --- p .--. q --.- r .-. s ... t - u ..- v ...- w .-- x -..- y -.-- z --.. 0 ----- 1 .---- 2 ..--- 3 ...-- 4 ....- 5 ..... 6 -.... 7 --... 8 ---.. 9 ----. . .-.-.- - -....- , ..--.. / -..- ; -.-.-. ( -.--. ) -.--. @ .--.- * ...-.- + .-.-. % .-... ! =---. $ ...-..-
这上面的就是摩尔斯码...我写在了txt文档当中...为了方便...但是我们需要注意一个地方就是我们在读取txt文档的时候,一定要把txt文档的对应内容拷贝到res/asset文件夹下面...或者是放在模拟器的内存卡中...千万别放在本地文件...因为Android的资源加载全在res文件夹下面或者是内存卡中,本地文件在正常的java程序中是可以读到的,但是在Android是一定读不到的..这个我已经试过,被坑3小时...因此这点需要注意....
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_1" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <EditText android:id="@+id/input" android:layout_height="wrap_content" android:layout_width="fill_parent" android:hint=""/> <Button android:id="@+id/translate" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/input" android:text="转换"/> <TextView android:id="@+id/show" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_below="@id/translate" android:text="输出"/> <EditText android:id="@+id/output" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_below="@id/show" android:enabled="false"/> <Button android:id="@+id/send" android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_below="@id/output" android:text="发送"/> </RelativeLayout>