Android多媒体功能的实现上(音频,视频,相机,录音)
2016-07-02 17:08
597 查看
在做App的时候,为了使App更加的吸引人,我们通常会加入一些多媒体功能,这也是Android中非常重要的功能之一,在刚学Android的时候,自己尝试着模仿QQ音乐做了一款音视频播放器,虽然做的不怎么样,但是大体的功能都实现了。在之后,我也不断的完善,有了一些自己的见解(源码地址都在文章末)。
首先是Android中的音频播放功能,在这里我主要涉及到的是MediaPlayer类,这个类中的方法不全讲,涉及到细节的我知道的也不是很多,主要还是要看源代码。在此我只来讲述它的使用。
播放音频文件,首先要找到它的位置,然后生成MediaPlayer的新对象,调用相应的方法,加载相应位置的文件,进行播放。
文件的位置主要包括三个来源:1用户在文件中自带的Resource资源2在SD卡或其它路径下的文件3网络上的文件
1播放Resource资源下的音频文件:
如果res文件夹下没有raw文件,直接新建一个raw文件,然后放入音频视频即可。
2播放SD卡或其他路径下的文件:
setDataSource函数的参数为你播放文件的位置,必须在start之前prepare,简单的四句代码,即可播放音乐
3播放网络上的文件:
我们是否感觉非常的简单,确实几句代码就搞定了,但是在实现了这个播放的效果后,我们会感觉功能很单一,怎样去暂停音乐后播放,怎样快进,快退音乐,怎样去通过进度条控制,为何关闭了当前的Activity,音乐还在播放。或者其他的一些功能,接下来我就以播放SD卡路径下的音乐作为例子来实现这些功能。(还会延伸一些知识点)
MediaPlayer常用的方法(如下图,看不懂可上网查阅)
功能1 :实现音乐的暂停播放和停止播放(需用到prepare ,start,pause,stop,reset函数,以按钮的形式实现)
以上三个函数可以实现播放当前暂停处的音乐,暂停哪里就播放哪里,停止播放为从头开始播放。使用了MediaPlayer提供的方法。此代码中最重要的一点是mediaplayer这个对象,也就是你new的这个对象,如果你只播放一首歌,那么就new 一次,如果你要播放很多歌那就new 很多次。也就是说new出的这个对象,代表着相对应你选择的歌曲的生命周期,所有的功能都在这个对象上完成。如果有很多歌,就多new几个。
功能 2 :使用进度条来控制音乐的快进快退,播放选到的位置,同步播放文件
此功能需要用到seekbar控件的功能,需要了解seekbar控件的方法
xml文件seekbar属性
以上xml文件显示的就是一个普通的进度条控件,现在需要对它进行操作,分为4个功能:
1 为进度条设置播放音频的时间长度,也就是说一个进度条代表一首歌的长度
这句代码使用了setMax方法和getDuration方法,获得当前mediaplayer对象的一首歌的长度然后赋值给进度条
2 使进度条能够与音频文件实现同步,音频文件播放到哪,进度条就在哪
这里同步的话,必须使用线程,主线程用来播放音乐,子线程用来同步音乐,用到了setProgress方法和getCurrentPosition方法,获得当前音乐文件的播放位置,然后赋值给seekbar.
3 显示当前音乐的播放时间和音乐的总时间
获取当前mediaplayer对象的长度,因为getDuration方法得到的是音乐文件的总时长也就是毫秒数,所有需要把它转换为正常的时间显示:
转化好后赋给TextView控件即可
4 实现拉动进度条,播放相对应的位置
实现OnSeekBarChangeListener接口,重写三个方法OnProgressChanged,OnStartTrackingTouch,OnStopTrackingTouch这三个方法
onProgressChanged方法:当进度条改变时,触发的操作
onStartTrackingTouch方法 :进度条刚开始拉动,触发的操作
onStopTrackingTouch
方法 :进度条停止拖动发生的操作
这四个功能实现后,就完成了一个简单的对音频文件的操作了,简单的功能就这样完成了,如果你想添加更多的复杂的功能,只需要在这个基础上自己改动即可,有什么不对的地方,还请大家指出,源代码中的音频的播放地址根据自己所放文件的地址填写。
源代码地址:http://download.csdn.net/detail/danielntz/9565737
在完成了以上的功能后,当我们关闭此程序后,发现音乐还在响,这是因为Mediaplayer本身是一个后台服务的类,它与程序也就是Activity是分开的,较好一点的理解就是程序是一个进程,Mediaplayer是一个进程,关闭程序只是把程序的进程关闭了,Mediaplayer的进程还在执行,所以音乐还在响。(我在魅族和中兴两部手机上做了测试,因为魅族系统是对Android系统的改进,所以有些情况不会发生,主要是关于底层是Android系统的)为了防止这种情况的发生,我们可以有以下两种做法
1 根据Activity的生命周期来控制Mediaplayer
<span style="font-size:18px;">@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mediaplayer.release();
mediaplayer = null;
endtongbu = false;
startService(new Intent(action));
Log.i(TAG, "guanbi");
}</span>
2 使用Service后台服务组件,把Mediaplayer类写在Service中(推荐使用这种类型,当把程序关掉后,音乐任然在进行,在后台,有源代码),主要分为四个步骤:
2.1 Service的配置(在配置文件中)
<service android:name="com.example.testboke.MusicService">
<intent-filter>
<action android:name="com.example.testboke.MusicService"/>
</intent-filter>
</service> MusicService为继承Service的类
2.2 Service中方法的覆盖
继承Servcie后通常会产生OnBind(),OnCreate(),OnStartCommand方法,通常当startService后,就会运行OnCreate()方法,然后是OnStartCommand()方法,之后如果再运行Service的话,就只运行OnStartCommand的方法,OnCreate()方法只在先前运行一次,除非stopService后,再startService后才执行OnCreate()方法,获取从Activity传过来的值是在OnStartCommand方法中获取
2.3 Activity与Service交互
2.3.1与普通的Activity与Activity之间的交互相同,通过Intent来进行数据的传递(Activity向Service传递数据)
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.start:
Bundle bundle = new Bundle();
bundle.putSerializable("start", "start");
startService(new Intent(action).putExtras(bundle));
receivewholetime = true;
break;
case R.id.pause:
Bundle bundle1= new Bundle();
bundle1.putSerializable("start", "pause");
startService(new Intent(action).putExtras( bundle1));
break;
case R.id.stop:
Bundle bundle2 = new Bundle();
bundle2.putSerializable("start", "stop");
startService(new Intent(action).putExtras(bundle2));
break;
}
}2.3.2 Service获取Activity传过来的数据(Service获取数据通常在OnStartCommand的方法中)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i(TAG, "sererere");
judgefunction = (String)intent.getExtras().getSerializable("start");
if(judgefunction.equals("start")){
try {
bofang();
endtongbu = true;
startthread = true;
if(startthread){
new Thread(new tongbu()).start();
startthread = false;
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(judgefunction.equals("pause")){
zanting();
}
if(judgefunction.equals("stop")){
tingzhi();
}
return super.onStartCommand(intent, flags, startId);
}
2.4 Service与Activity交互(有很多种方法,在此使用BroadCast广播类方法)
2.4.1注册广播接收 //注册广播接收
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(action);
SurfaceFunction.this.registerReceiver(receiver, filter);2.4.2接收广播(Activity获取Service传递过来的数据)
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(receivewholetime){
int time = intent.getExtras().getInt("wholetime");
longshijian1 = new haomiaotoshijian().formattime(time); //歌曲总时间转换格式
Log.i(TAG, "总时间" + longshijian1);
wholetime.setText(longshijian1);
seekbar.setMax(time);
receivewholetime = false;
}
int progress = (int)intent.getExtras().getInt("progress");
seekbar.setProgress(progress);
String currenttimeone = new haomiaotoshijian().formattime(progress);
currenttime.setText(currenttimeone);
}
}2.4.3发送广播(Service向Activity发送数据)
//发送广播
Intent intent=new Intent();
intent.putExtra("wholetime", longshijian);
intent.setAction("com.example.testboke.MusicService");
sendBroadcast(intent);上述就是完整的步骤,希望大家也可以给出我建议,以Service形式的mini音频播放器源代码地址:http://download.csdn.net/detail/danielntz/9575869
有一些功能我自己就没有实现了,比如进度条控制的快进快退,有兴趣的同学可以自己试着写,这个代码运行后,关闭了程序后,音乐还在播放,如果想停止,就在你需要停止的地方添加stopService方法即可
首先是Android中的音频播放功能,在这里我主要涉及到的是MediaPlayer类,这个类中的方法不全讲,涉及到细节的我知道的也不是很多,主要还是要看源代码。在此我只来讲述它的使用。
播放音频文件,首先要找到它的位置,然后生成MediaPlayer的新对象,调用相应的方法,加载相应位置的文件,进行播放。
文件的位置主要包括三个来源:1用户在文件中自带的Resource资源2在SD卡或其它路径下的文件3网络上的文件
1播放Resource资源下的音频文件:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">if(this.player == null){ // this.player = new MediaPlayer(); this.player = MediaPlayer.create(context, R.raw.a1); // this.player.prepare() ; } //监听器判断是否结束 this.player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { // TODO Auto-generated method stub stop(); } }); this.player.start(); }</span></span></span></span>
如果res文件夹下没有raw文件,直接新建一个raw文件,然后放入音频视频即可。
2播放SD卡或其他路径下的文件:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"> MediaPlayer mediaplayer = new MediaPlayer(); //生成一个MediaPlayer的对象 mediaplayer.setDataSource("/sdcard/Wiz Khalifa-See you again.mp3"); //装载音频文件的位置 mediaplayer.prepare(); //准备 mediaplayer.start(); //开始播放</span></span></span>
setDataSource函数的参数为你播放文件的位置,必须在start之前prepare,简单的四句代码,即可播放音乐
3播放网络上的文件:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">Uri uri = Uri.parse("http://192.168.0.135:8080/jsonweb/WebRoot/musics/starj.mp3"); // Uri uri = Uri.parse("http://192.168.0.135:8080/raw1/starj.mp3"); media = MediaPlayer.create(startmusic.this, uri); media.setOnPreparedListener(new OnPreparedListener(){ @Override public void onPrepared(MediaPlayer mp) { // TODO Auto-generated method stub media.start(); } });</span></span></span>
我们是否感觉非常的简单,确实几句代码就搞定了,但是在实现了这个播放的效果后,我们会感觉功能很单一,怎样去暂停音乐后播放,怎样快进,快退音乐,怎样去通过进度条控制,为何关闭了当前的Activity,音乐还在播放。或者其他的一些功能,接下来我就以播放SD卡路径下的音乐作为例子来实现这些功能。(还会延伸一些知识点)
MediaPlayer常用的方法(如下图,看不懂可上网查阅)
功能1 :实现音乐的暂停播放和停止播放(需用到prepare ,start,pause,stop,reset函数,以按钮的形式实现)
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">//播放音乐 public void bofang() throws IllegalStateException, IOException { if( mediaplayer == null){ mediaplayer = new MediaPlayer(); //生成一个MediaPlayer的对象 mediaplayer.setDataSource("/sdcard/Wiz Khalifa-See you again.mp3"); //装载音频文件的位置 } if(flag == 0 || flag == 2) mediaplayer.prepare(); //准备 mediaplayer.start(); //开始播放 } //暂停音乐 public void zanting(){ if(mediaplayer != null && mediaplayer.isPlaying()){ mediaplayer.pause(); flag =1; } } //停止音乐 public void tingzhi(){ if(mediaplayer != null && mediaplayer.isPlaying()){ mediaplayer.stop(); mediaplayer.reset(); //使mediapalyer处于空闲状态</span>
<span style="font-size:18px;"> mediaplayer.release(); //切记停止音乐后,一定要把它释放掉 mediaplayer = null; //使mediaplayer为空 flag =2; } }</span></span></span></span>
以上三个函数可以实现播放当前暂停处的音乐,暂停哪里就播放哪里,停止播放为从头开始播放。使用了MediaPlayer提供的方法。此代码中最重要的一点是mediaplayer这个对象,也就是你new的这个对象,如果你只播放一首歌,那么就new 一次,如果你要播放很多歌那就new 很多次。也就是说new出的这个对象,代表着相对应你选择的歌曲的生命周期,所有的功能都在这个对象上完成。如果有很多歌,就多new几个。
功能 2 :使用进度条来控制音乐的快进快退,播放选到的位置,同步播放文件
此功能需要用到seekbar控件的功能,需要了解seekbar控件的方法
xml文件seekbar属性
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"> <SeekBar android:id="@+id/progress_bar" android:layout_width="300dip" android:layout_height="wrap_content" android:maxHeight="20dip" android:minHeight="15dip" android:paddingLeft="18dip" android:paddingRight="18dip" android:max="100"/></span></span></span>
以上xml文件显示的就是一个普通的进度条控件,现在需要对它进行操作,分为4个功能:
1 为进度条设置播放音频的时间长度,也就是说一个进度条代表一首歌的长度
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">seekbar.setMax(mediaplayer.getDuration()); //给seekbar添加具体的时间</span></span></span></span>
这句代码使用了setMax方法和getDuration方法,获得当前mediaplayer对象的一首歌的长度然后赋值给进度条
2 使进度条能够与音频文件实现同步,音频文件播放到哪,进度条就在哪
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"> <span style="font-size:18px;">public class seekbartongbu implements Runnable{ @Override public void run() { // TODO Auto-generated method stub while(true){ try { Thread.sleep(1000); seekbar.setProgress(mediaplayer.getCurrentPosition()); //获得当前播放的进度值 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }</span></span></span></span>
这里同步的话,必须使用线程,主线程用来播放音乐,子线程用来同步音乐,用到了setProgress方法和getCurrentPosition方法,获得当前音乐文件的播放位置,然后赋值给seekbar.
3 显示当前音乐的播放时间和音乐的总时间
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"> <TextView android:id="@+id/currentiem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dip" android:text="当前时间"/> <TextView android:id="@+id/wholetime" android:layout_width="wrap_content" android:layout_marginTop="5dip" android:layout_height="wrap_content" android:text="总时间"/> 用两个Textview控件来显示时间,并且把它们俩放到seekbar的两端 longshijian = mediaplayer.getDuration(); longshijian1 = new haomiaotoshijian().formattime(longshijian); zongshijian.setText(longshijian1);</span></span></span>
获取当前mediaplayer对象的长度,因为getDuration方法得到的是音乐文件的总时长也就是毫秒数,所有需要把它转换为正常的时间显示:
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">public class haomiaotoshijian { public haomiaotoshijian(){ } //把毫秒数变成时间格式 如 01:00 public String formattime(long time){ time = time/ 1000; String strHour = "" + (time/3600); String strMinute = "" + time%3600/60; String strSecond = "" + time%3600%60; strHour = strHour.length() < 2? "0" + strHour: strHour; strMinute = strMinute.length() < 2? "0" + strMinute: strMinute; strSecond = strSecond.length() < 2? "0" + strSecond: strSecond; String strRsult = ""; if (!strHour.equals("00")) { strRsult += strHour + ":"; } if (!strMinute.equals("00")) { strRsult += strMinute + ":"; } strRsult += strSecond; return strRsult; }</span></span></span></span>
转化好后赋给TextView控件即可
4 实现拉动进度条,播放相对应的位置
实现OnSeekBarChangeListener接口,重写三个方法OnProgressChanged,OnStartTrackingTouch,OnStopTrackingTouch这三个方法
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">@Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub String nowtime = new haomiaotoshijian().formattime(progress); //Log.i(TAG, progress+""); new chuandishuju().setCurrentprogress(progress); if(nowtime.contains(":")){ bofangshijian.setText(nowtime); } else bofangshijian.setText("00:"+nowtime); } @Override public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } @Override public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub if(bofangmusic.player != null) bofangmusic.player.seekTo(seekbar.getProgress()); else{ xiayishoumusic.player.seekTo(seekbar.getProgress()); } }</span> </span></span></span>
onProgressChanged方法:当进度条改变时,触发的操作
onStartTrackingTouch方法 :进度条刚开始拉动,触发的操作
onStopTrackingTouch
方法 :进度条停止拖动发生的操作
这四个功能实现后,就完成了一个简单的对音频文件的操作了,简单的功能就这样完成了,如果你想添加更多的复杂的功能,只需要在这个基础上自己改动即可,有什么不对的地方,还请大家指出,源代码中的音频的播放地址根据自己所放文件的地址填写。
源代码地址:http://download.csdn.net/detail/danielntz/9565737
在完成了以上的功能后,当我们关闭此程序后,发现音乐还在响,这是因为Mediaplayer本身是一个后台服务的类,它与程序也就是Activity是分开的,较好一点的理解就是程序是一个进程,Mediaplayer是一个进程,关闭程序只是把程序的进程关闭了,Mediaplayer的进程还在执行,所以音乐还在响。(我在魅族和中兴两部手机上做了测试,因为魅族系统是对Android系统的改进,所以有些情况不会发生,主要是关于底层是Android系统的)为了防止这种情况的发生,我们可以有以下两种做法
1 根据Activity的生命周期来控制Mediaplayer
<span style="font-size:18px;">@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mediaplayer.release();
mediaplayer = null;
endtongbu = false;
startService(new Intent(action));
Log.i(TAG, "guanbi");
}</span>
2 使用Service后台服务组件,把Mediaplayer类写在Service中(推荐使用这种类型,当把程序关掉后,音乐任然在进行,在后台,有源代码),主要分为四个步骤:
2.1 Service的配置(在配置文件中)
<service android:name="com.example.testboke.MusicService">
<intent-filter>
<action android:name="com.example.testboke.MusicService"/>
</intent-filter>
</service> MusicService为继承Service的类
2.2 Service中方法的覆盖
继承Servcie后通常会产生OnBind(),OnCreate(),OnStartCommand方法,通常当startService后,就会运行OnCreate()方法,然后是OnStartCommand()方法,之后如果再运行Service的话,就只运行OnStartCommand的方法,OnCreate()方法只在先前运行一次,除非stopService后,再startService后才执行OnCreate()方法,获取从Activity传过来的值是在OnStartCommand方法中获取
2.3 Activity与Service交互
2.3.1与普通的Activity与Activity之间的交互相同,通过Intent来进行数据的传递(Activity向Service传递数据)
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.start:
Bundle bundle = new Bundle();
bundle.putSerializable("start", "start");
startService(new Intent(action).putExtras(bundle));
receivewholetime = true;
break;
case R.id.pause:
Bundle bundle1= new Bundle();
bundle1.putSerializable("start", "pause");
startService(new Intent(action).putExtras( bundle1));
break;
case R.id.stop:
Bundle bundle2 = new Bundle();
bundle2.putSerializable("start", "stop");
startService(new Intent(action).putExtras(bundle2));
break;
}
}2.3.2 Service获取Activity传过来的数据(Service获取数据通常在OnStartCommand的方法中)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i(TAG, "sererere");
judgefunction = (String)intent.getExtras().getSerializable("start");
if(judgefunction.equals("start")){
try {
bofang();
endtongbu = true;
startthread = true;
if(startthread){
new Thread(new tongbu()).start();
startthread = false;
}
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(judgefunction.equals("pause")){
zanting();
}
if(judgefunction.equals("stop")){
tingzhi();
}
return super.onStartCommand(intent, flags, startId);
}
2.4 Service与Activity交互(有很多种方法,在此使用BroadCast广播类方法)
2.4.1注册广播接收 //注册广播接收
receiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(action);
SurfaceFunction.this.registerReceiver(receiver, filter);2.4.2接收广播(Activity获取Service传递过来的数据)
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(receivewholetime){
int time = intent.getExtras().getInt("wholetime");
longshijian1 = new haomiaotoshijian().formattime(time); //歌曲总时间转换格式
Log.i(TAG, "总时间" + longshijian1);
wholetime.setText(longshijian1);
seekbar.setMax(time);
receivewholetime = false;
}
int progress = (int)intent.getExtras().getInt("progress");
seekbar.setProgress(progress);
String currenttimeone = new haomiaotoshijian().formattime(progress);
currenttime.setText(currenttimeone);
}
}2.4.3发送广播(Service向Activity发送数据)
//发送广播
Intent intent=new Intent();
intent.putExtra("wholetime", longshijian);
intent.setAction("com.example.testboke.MusicService");
sendBroadcast(intent);上述就是完整的步骤,希望大家也可以给出我建议,以Service形式的mini音频播放器源代码地址:http://download.csdn.net/detail/danielntz/9575869
有一些功能我自己就没有实现了,比如进度条控制的快进快退,有兴趣的同学可以自己试着写,这个代码运行后,关闭了程序后,音乐还在播放,如果想停止,就在你需要停止的地方添加stopService方法即可
相关文章推荐
- 解决Android版vlc中文乱码问题
- android studio下生成jni头文件
- Zxing二维码扫描(Android开源库)
- android thread
- Launcher3桌面Icon的文字size的 修改
- 自定义文件管理器
- Android开发时,写MainActivity.java时出现TextView cannot be resolved to a type
- android 波形图
- Android中使用FragmentManager获得控件
- Android canvas.drawArc() 画圆弧
- Android图像开源视图:SmartImageView
- android surfaceView+mediaPlayer 自定义视频播放器
- 如何使用android studio进行多渠道的打包?
- android studio基本界面设置
- android 底部弹出提示框的实现方式
- Android变色状态栏实现
- Android自定义圆角矩形图片ImageView
- android连接wifi
- android下基于开源浏览器项目crosswalk的js与java交互
- Android: Resource Type Animation