Android基础笔记(十七)- 多媒体编程
- MediaPlayer播放音频的基本使用
- 音乐播放器的完善
- 视频播放SurfaceView
- 视频播放VideoView
- vitamio框架
- 如何调用照相机和录像机
MediaPlayer播放音频的基本使用
-
MediaPlayer
播放音频的基本使用步骤: -
①创建一个
MediaPlayer
实例 - ②设置播放的数据格式
- ③设置数据源
- ④准备播放
- ⑤开始播放
整体的示例代码很简单:
// 1. 创建一个音频播放器实例
final MediaPlayer player = new MediaPlayer();
// 2. 设置数据格式
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource("/mnt/sdcard/zxxpg.mp3");// 此处也可以是网络路径
// player.prepare(); // 此处会阻塞主线程,建议prepareAsync
player.prepareAsync();
// 4. 当准备成功后回调
player.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// 5. 开始播放player.start();}
});
音乐播放器的完善
下面是音乐播放器案例教完善的实现,当然这也只是个玩具程序,还缺少很多很多功能。
- 该案例的实现分为以下几步:
- ①点击播放、暂停、继续按钮达到播放、暂停、继续的目的
- ②增加进度条,让进度随着播放进度而调整
- ③手指拖动进度条时,可以修改播放的位置。
- ④使用文字显示当前播放进度
本来想把代码直接贴出来完事的,但是感觉这样不太好,了解代码的演化过程可能是对自己最好的锻炼。
由于这个小案例是在之前案例的基础之上修改过来了,所以先把骨架代码贴出来,然后再一步一步增加功能。
IService接口如下
public interface IService {public void callPlay();public void callPause();public void callReplay();
}
MainActivity类如下:
public class MainActivity extends Activity implements OnSeekBarChangeListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);// 启动和绑定服务Intent service = new Intent(this, MusicService.class);startService(service);conn = new MyServiceConnection();bindService(service, conn, Context.BIND_AUTO_CREATE);}// 播放public void play(View v) {iService.callPlay();}// 暂停public void pause(View v) { iService.callPause();}// 重新播放public void replay(View v) { iService.callReplay();}private class MyServiceConnection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iService = (IService) service; }@Overridepublic void onServiceDisconnected(ComponentName name) {}}@Overrideprotected void onDestroy() {super.onDestroy();unbindService(conn);}
}
MusicService类文件如下:
public class MusicService extends Service {@Overridepublic void onCreate() {super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}// 播放音乐public void play() {}// 暂停public void pause() {}// 继续播放public void replay() {}// 中间人private class MyBinder extends Binder implements IService {@Overridepublic void callPlay() { play(); }@Overridepublic void callPause() {pause();}@Overridepublic void callReplay() {replay();}}
}
activity_main.xml文件如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity" ><Button
android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="play"android:text="播放音乐" /><Button
android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="pause"android:text="暂停播放" /><Button
android:layout_width="match_parent"android:layout_height="wrap_content"android:onClick="replay"android:text="继续播放音乐" />
</LinearLayout>
整体来说骨架代码还是很简单的,当应用启动时会启动并绑定服务,这样就可以通过中间人来调用服务中的方法了。
接下来就一步一步添加功能。
第一步,点击播放、暂停、继续按钮达到播放、暂停、继续的目的
首先回想一下如何播放音乐文件:初始化MediaPlay
实例,配置数据源、类型,准备一下,然后就可以start播放了。
那么在这一步中,可以在服务的onCreate()
方法中,实例化MediaPlay
对象;当调用播放时,初始化资源并播放;暂停和继续播放就很简单了,只需要调用相应的方法就OK了。
增加的代码如下:
// 播放器实例
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {super.onCreate();// 初始化实例对象mediaPlayer = new MediaPlayer();
}// 播放
public void play() {
try {// 重置资源mediaPlayer.reset();// 初始化配置mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource("/mnt/sdcard/zuoqujia.mp3");// 准备mediaPlayer.prepareAsync();// 准备完成的回调mediaPlayer.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {mediaPlayer.start();}});} catch (Exception e) {e.printStackTrace();}
}// 暂停播放
public void pause() {mediaPlayer.pause();}// 继续播放
public void replay() {mediaPlayer.start();}
第二步,增加进度条,让进度随着播放进度而调整
其实增加一个进度条是很简单的,直接拖一个SeekBar
就可以达到目的。但是怎么样在服务中达到修改UI的目的却是这一步的难点,此外,SeekBar的进度条是要实时更新的,这些都是这一步的关键。
仔细回想一下之前的知识点,我们可以使用Handler在子线程中修改UI线程的数据,但是服务中怎么获取到Handler?可以这样,把MainActivity中的Handler改变为静态变量,这样就可以在服务类中使用了。
音乐播放要求每秒更新一次进度条的位置,我们可以使用SE中的Timer和TimerTask达到此目的。
有了以上这些解决问题的技术,赶快来看看代码是怎么写的。
首先在布局文件中加入SeekBar控件,并在MainActivity的找到该控件。
<SeekBar
android:id="@+id/sb_progress"android:layout_width="match_parent"android:layout_height="wrap_content" />
private static SeekBar sbProgress; // 进度条protected void onCreate(Bundle savedInstanceState) {... ...sbProgress = (SeekBar) findViewById(R.id.sb_progress);... ...
}
然后在MainActivity中增加静态的Handler,在MusicService类增加发送消息的逻辑。
MainActivity类增加如下内容:
private static int duration; // 歌曲总时长,毫秒单位 private static int currentPosition; // 歌曲当前进度,毫秒单位public static Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case MusicService.CURRENTPOSITION: // 设置进度// 获取消息、更新进度条、更新当前播放位置currentPosition = msg.arg1;sbProgress.setProgress(currentPosition);break;case MusicService.DURATION: // 设置总时长duration = msg.arg1;sbProgress.setMax(duration);break;default:break;}};
};
MusicService增加如下代码
public static final int DURATION = 0; // 音乐总时长
public static final int CURRENTPOSITION = 1;//音乐当前播放位置public void play() {try {// 重置mediaPlayer.reset();// 初始化mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource("/mnt/sdcard/zuoqujia.mp3");// 准备mediaPlayer.prepareAsync();// 准备完成的回调mediaPlayer.setOnPreparedListener(new OnPreparedListener() {@Overridepublic void onPrepared(MediaPlayer mp) {// 开始播放mediaPlayer.start();// 获取音乐总进度,并发送消息int duration = mediaPlayer.getDuration();Message msg = Message.obtain();msg.what = DURATION;msg.arg1 = duration;MainActivity.handler.sendMessage(msg);// 每隔一秒更新进度Timer timer = new Timer();TimerTask task = new TimerTask() {@Overridepublic void run() {// 获取当前进度,并发送消息更新UIint currentPosition = mediaPlayer.getCurrentPosition();Message msg = Message.obtain();msg.what = CURRENTPOSITION;msg.arg1 = currentPosition;MainActivity.handler.sendMessage(msg);}};// 每隔一秒钟调用一次timer.schedule(task, 0, 1000);}});} catch (Exception e) {e.printStackTrace();}
}
做完这些,音乐播放时,进度到就会“动”了。
第三步,手指拖动进度条时,可以修改播放的位置。
达到这个目的,可以利用MediaPlayer
中的seekTo()
方法,定位播放位置。
那么我们需要做的很简单了,在IService中增加一个callSeekToProgress()
方法,并在MainActivity和MusicService调用和编写。
IService增加如下内容:
public void callSeekToProgress(int currentPosition);
MainActivity增加如下内容:
// 把播放进度移动到指定位置
public void seekToProgress(int currentPosition) {iService.callSeekToProgress(currentPosition);
}
在MusicService增加如下内容:
// 中间人
private class MyBinder extends Binder implements IService {... ...@Overridepublic void callSeekToProgress(int currentPosition) {seekToProgress(currentPosition);}
}// 修改播放位置
public void seekToProgress(int currentPosition) {mediaPlayer.seekTo(currentPosition);
}
第四步,使用文字显示当前播放进度
写完上面这些,增加这个功能就略显容易了。在布局文件中增加一个TextView
,然后再Handler消息处理时,设置其内容就可以了。
tvCurrentProgress.setText("音乐共" + (int)(duration / 1000.0f) + "秒/当前" + (int)(currentPosition / 1000.0f) + "秒");
视频播放(SurfaceView)
Android中的视频播放使用的还是MediaPlayer
类,同时还借助了SurfaceView
控件,而且遗憾的是它只支持3GP和MP4格式的文件。
代码也很简单,简单的看看一下吧
// 获取到控件
SurfaceView sfv = (SurfaceView) findViewById(R.id.sfv);// 播放器
final MediaPlayer mediaPlayer = new MediaPlayer();SurfaceHolder holder = sfv.getHolder();// 添加回调,当SurfaceView准备好时才播放
holder.addCallback(new Callback() {@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {}@Overridepublic void surfaceCreated(SurfaceHolder holder) {try {// 设置HoldermediaPlayer.setDisplay(holder);mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource("/mnt/sdcard/proto.3gp");mediaPlayer.prepare(); // might take long! (for buffering, etc)mediaPlayer.start();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
});
视频播放(VideoView)
上面的SurfaceView略显麻烦,Google为我们提供了另外一个封装的控件VideoView
,只需要几行代码就可以轻松展示一个3GP或者MP4文件。
VideoView vv = (VideoView) findViewById(R.id.vv);
vv.setVideoPath("/mnt/sdcard/proto.3gp");
vv.start();
vitamio框架
Android原生的SurfaceView和VideoView,在播放视频格式上都有限制,只能播放3GP和MP4。
Vitamio是一款开源框架,由一大堆C大神开发的,其中提供了Andoird版本的类库支持。
其中有一个VideoView类,和Andoird中原生的VideoView方法差不多,但是完美支持市面上的各种视频格式。
<io.vov.vitamio.widget.VideoView
android:id="@+id/vv"android:layout_width="wrap_content"android:layout_height="wrap_content" />
io.vov.vitamio.widget.VideoView vv = (VideoView) findViewById(R.id.vv);vv.setVideoPath("/mnt/sdcard/test.3gp");
使用方法也是超级简单。
如何调用照相机和录像机
//就是利用隐式意图 去开启手机的自带的相机应用
//如果是照相
//创建意图对象
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath(),"paizhao.png"))); // set the image file name
//开启意图 获取结果
startActivityForResult(intent, 0);//如果是录像
//创建意图对象
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath(),"luxiang.3gp"))); // set the image file name//开启意图 获取结果
startActivityForResult(intent, 0);
Android基础笔记(十七)- 多媒体编程相关推荐
- Bootstrap基础二十七 多媒体对象(Media Object)
Bootstrap<基础二十七> 多媒体对象(Media Object) 原文:Bootstrap<基础二十七> 多媒体对象(Media Object) Bootstrap 中 ...
- android基础笔记
1 拨打电话 Intent意图 //系统统一调用程序的一个类 Stringnumber="13138794688"; Intent intent=new Intent( ...
- 【Android基础笔记01】Android开发环境搭建和HelloWorld
最近手头项目3.0版本要上线了, 没有那么多工作压力了, 抽空看了看之前在云笔记上做的笔记 都是一些基础知识 给大家分享出来吧 一.什么是Android?[了解 ] Android(中文俗称安卓)是一 ...
- Android学习笔记十七.使用ContentProvider实现数据共享(四).操作系统(联系人)的ContentProvider
Android系统本身提供了大量的ContentProvider,例如联系人信息.系统的多媒体信息等,我们开发的应用程序主要是通过ContentResolver来调用系统的ContentPro ...
- android基础笔记1
1. 在模拟器中安装apk文件: G:\work\android-sdk-windows\platform-tools里有个adb.exe工具 Adb install G:\work\Cr ...
- 【Android基础】应用界面编程
介绍 本章会介绍Android程序界面和很多组件的知识,是界面需要的知识. 通过学习本章的知识,可以开发出漂亮的图形用户界面,这些图形用户界面是Android应用开发的基础,也是非常重要的组成部分. ...
- android开发笔记之多媒体—图形图像处理
--图像的两种分类: 位图 例子:单色位图(只有两种颜色(黑白),每一个像素点占一位)256位图(每一个像素点有256个颜色,每一个像素点需要占一个字节)24位位图(每个像素点占3个字节)位图图像(b ...
- Android学习笔记——手机多媒体运用
参考书籍:Android第一行代码(第二版).郭霖著 1.通知 Notification是Android中较有特色的功能,当应用程序希望向用户发出提示信息但不在前台运行时可使用(手机顶部显示通知图标, ...
- android开发笔记之网络编程—简易新闻客户端
今天我们来对前面讲过的知识综合运用一下,包括xml的PULL解析,listView的万能适配器等知识.... 那先来看一个组件-->智能图片加载器(smart-image-view),它可以很方 ...
最新文章
- HAAR、LBP分类器训练
- JVM 史上最最最完整知识总结!
- 跟着 Github 学习 Restful HTTP API 的优雅设计
- android activity启动模式_从0系统学Android--2.5Activity启动模式
- 矩池云上编译安装dlib库
- 档案盒正面标签制作_如何制作差异化的短视频内容?
- AtCoder Grand Contest 018 A
- 一张图搞懂美国大数据产业(上)
- IDEA java 中文乱码解决方法
- JavaScript逻辑训练题(二)
- diskgenius扩容c盘重启电脑卡住_DiskGenius怎么给C盘扩容?DiskGenius无损调整C盘容量方法 (全文)...
- 个人博客详细文章目录索引(持续更新)
- QNX 7.1 交叉编译 cron
- 如何将图片变成GIF图?一键完成gif制作
- 复习——哈夫曼树及哈夫曼编码
- CSS首字母下沉怎么设置?
- 重识JavaScript(一)
- 利用硬件机器人实现网络试衣
- Selenium WebDrive学习(一)
- 盲打软件测试自学,GS Typing Tutor(打字练习测试软件) V3.1 官方版
热门文章
- 北理Todo::待办管理系统
- 前端利用numeral处理数字和时间格式化
- 下拉选框样式html,超酷select选择下拉框美化jQuery插件
- 常见胸肌问题解答(一):厚度不够
- 嫌自己的签名不好看?那就用Python给自己设计一个专属签名
- flutter开发工具,2020年最全Android面试攻略
- R语言 cannot take a sample larger than the population when ‘replace = FALSE‘
- Python-docx
- java调用hp打印机驱动_Java Equip.getHp方法代码示例
- mc一进服务器就未响应,大佬们这得怎么办啊,一进服务器游戏就崩溃,