您的位置:首页 > 其它

媒体播放之MediaPlayer|三种媒体源|音乐播放器源码|服务中使用|前台运行|处理音频|检索本地歌曲焦点

2017-09-04 11:00 696 查看

简介

详解传送门:http://blog.csdn.net/hejjunlin/article/details/52349221

大家好我们今天研究的是Android中很重要也最为复杂的媒体播放器—MediaPlayer.Android的MediaPlayer包含了Audio和video的播放功能,

在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。

官方原图



另外翻译了整张图,不敢独享,献给大家:



MediaPlayer类可用于控制音频/视频文件和流的播放或回放(playback)。

1.状态图:
idle表示空闲的意思,音频/视频文件和流的播放控制是使用一个状态机进行管理。下图显示了生命周期,并支持播放控制操作驱动的MediaPlayer对象的状态。椭圆表示一个MediaPlayer对象可以驻留在的状态。所述弧线表示驱动对象的状态过渡的重放控制操作。有两种类型的弧线。具有单箭头头部的弧线表示同步方法调用,而那些与双箭头表示异步方法调用。


MediaPlayer播放三种媒体源的播放方式

注意如果你要访问网络就要添加网络的权限:

<uses-permission android:name=”android.permission.INTERNET”/>


package com.example.kaifaceshi;

import java.io.IOException;

import android.R.string;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;

public class mediapalyer extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.mediaplayer);

}
//播放本地资源文件
public void button1(View v) {
MediaPlayer mp=MediaPlayer.create(this,R.raw.music2);
mp.start();
}
//播放系统资源文件
public void button2(View v) {
MediaPlayer mp=new MediaPlayer();
String path=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+"/music.mp3";

try {
mp.setDataSource(this,Uri.parse(path));
mp.prepare();
mp.start();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//播放网络资源文件
public void button3(View v) {
String s="http://sc1.111ttt.com:8282/2017/1/05/09/298092042172.mp3?tflag=1504463364&pin=2801bde72cb71934f7a67ea7b3049202";
MediaPlayer mp=new MediaPlayer();
try {
mp.setDataSource(this,Uri.parse(s));
mp.setOnPreparedListener(new OnPreparedListener() {

@Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.start();
}
});
mp.prepareAsync();

} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


简单的音乐播放器源码

效果图:



package com.example.simplemediaplkay;

import java.io.IOException;
import java.util.ArrayList;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import androi
4000
d.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
/*
* 此类实现了:
* OnClickListener//当按钮点击后调用此监听
* OnPreparedListener//当异步解析完成后调用此监听
* OnErrorListener//当播放错误后掉用此监听
* OnCompletionListener//当播放完音乐后调用此监听
*/
public class MainActivity extends Activity implements OnClickListener,
OnPreparedListener,OnErrorListener,OnCompletionListener{
private ImageView iv;
private Button button_play,button_pause,button_next,button_up;

private MediaPlayer mp;
//表示当前要播放音乐的索引
private int index=0;
//控制当前的播放状态 true表示暂停状态 ,false表示播放状态
private boolean isPause=false;

ArrayList<String> musicList=new ArrayList<String>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mp=new MediaPlayer();

initUI();
initMusecList();

mp.setOnPreparedListener(this);
mp.setOnErrorListener(this);
mp.setOnCompletionListener(this);

//设置旋转动画
iv=(ImageView) findViewById(R.id.imageView1);
//用Java code实现
RotateAnimation rotate  = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
LinearInterpolator lin = new LinearInterpolator();
rotate.setInterpolator(lin);
rotate.setDuration(1500);//设置动画持续时间
rotate.setRepeatCount(-1);//设置重复次数
rotate.setFillAfter(true);//动画执行完后是否停留在执行完的状态
rotate.setStartOffset(10);//执行前的等待时间
iv.setAnimation(rotate);
}
//初始化音乐添加到集合中去
private void initMusecList() {
String musicPath=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath();
musicList.add(musicPath+"/"+"list1.mp3");
musicList.add(musicPath+"/"+"list2.mp3");
musicList.add(musicPath+"/"+"list3.mp3");
musicList.add(musicPath+"/"+"list4.mp3");
musicList.add(musicPath+"/"+"list5.mp3");
musicList.add(musicPath+"/"+"list6.mp3");
musicList.add(musicPath+"/"+"list7.mp3");
musicList.add(musicPath+"/"+"list8.mp3");
musicList.add(musicPath+"/"+"list9.mp3");
musicList.add(musicPath+"/"+"list10.mp3");
}

//初始化音乐
private void initUI() {
button_play=(Button) findViewById(R.id.play);
button_pause=(Button) findViewById(R.id.pause);
button_next=(Button) findViewById(R.id.next);
button_up=(Button) findViewById(R.id.up);
//注册按钮的事件
button_play.setOnClickListener(this);
button_pause.setOnClickListener(this);
button_next.setOnClickListener(this);
button_up.setOnClickListener(this);
}
//*********************主按钮点击判断方法*********************
@Override
public void onClick(View v) {

switch (v.getId()) {
case R.id.play://点击播放按钮 //状态1(第一次播放状态) 状态2(播放暂停状态)
paly();
Toast.makeText(getApplicationContext(), index+"", 1000).show();
break;
case R.id.pause://点击暂停按钮
pause();
Toast.makeText(getApplicationContext(), index+"", 1000).show();
break;
case R.id.next://点击下一首按钮
next();
Toast.makeText(getApplicationContext(), index+"", 1000).show();
break;
case R.id.up://点击上一首按钮
up();
Toast.makeText(getApplicationContext(), index+"", 1000).show();
break;
}

}

//*********************自己写的播放状态监测方法***************
//播放方法
private void paly() {
if(isPause) {
mp.start();//如果是暂停状态直接开始播放
isPause=false;//是否为暂停状态

}else {
start();//调用start方法

}

}
//重头开始播放音乐
private void start() {
if(index<musicList.size()) {

if(mp.isPlaying())mp.stop();//如果现在正在播发,就先停止
mp.reset();//重置一下

String musicPath=musicList.get(index);//从集合中获取音乐播放路径
try {
mp.setDataSource(musicPath);
//异步加载
mp.prepareAsync();
isPause=false;//是否为暂停状态

} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
}
//暂停方法
private void pause() {
if(mp.isPlaying()) {
mp.pause();
isPause=true;//把是否为暂停状态设置为true;
}
}
//下一首方法
private void next() {
if(index+1<musicList.size()) {
index++;
}else {
index=0;
}
start();

}
//上一首方法
private void up() {
if(index-1>=0) {
index--;

}else {
index=musicList.size()-1;
}
start();

}
//******************************************************
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//如果播放错误了我们就直接调用重置的方法
mp.reset();
return true;
}
@Override
public void onPrepared(MediaPlayer mp) {
//当异步加载完成
mp.start();
}
@Override
public void onCompletion(MediaPlayer mp) {
//如果播放完成了我们就直接调用播放下一首的方法
next();
}

//当Activity销毁了我们释放资源
@Override
protected void onDestroy() {
super.onDestroy();
if(mp!=null) {
if(mp.isPlaying())mp.stop();
mp.release();//释放资源
}
}
}


服务中使用MediaPlayer

MainActivity.java

package com.example.sevicesmediaplayer;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void play(View v) {
Intent intent=new Intent("com.music.ACTION_PLAY");
startService(intent);
}
public void pause(View v) {
Intent intent=new Intent("com.music.ACTION_PAUSE");
startService(intent);
}
public void exit(View v) {
Intent intent=new Intent("com.music.ACTION_EXIT");
startService(intent);
}
}


MusicService.java

package com.example.sevicesmediaplayer;

import java.io.IOException;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
/*
* 注意!!!如果你要给MediaPlayer加锁那么你要添加以下全限,不然会报错
*
*  <uses-permission android:name="android.permission.WAKE_LOCK"/>
*/
public class MusicService extends Service implements OnPreparedListener{

public static final String ACTION_PLAY="com.music.ACTION_PLAY";
public static final String ACTION_PAUSE="com.music.ACTION_PAUSE";
public static final String ACTION_EXIT="com.music.ACTION_EXIT";
private MediaPlayer mp;
WifiLock lock;
public MusicService() {

}
@Override
public void onCreate() {
super.onCreate();
mp=new MediaPlayer();
//给MediaPlayer加CPU锁
//保持CPU正常运转
mp.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);;
//给MediaPlayer加WIFI锁
//保持WIFI不被休眠
WifiManager manager=(WifiManager) getSystemService(Context.WIFI_SERVICE);
lock=manager.createWifiLock("mylock");
lock.acquire();
mp.setOnPreparedListener(this);
}
//再次方法中触发相应的事件
@Override
public int onStartCommand(Intent intent, int flags, int startId) {

String action=intent.getAction();
if(ACTION_PLAY.equals(action)) {
mp.reset();
try {
mp.setDataSource(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)+"/"+"list1.mp3");

mp.prepareAsync();

} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}else if(ACTION_PAUSE.equals(action)) {
if(mp.isPlaying())mp.pause();
}else if(ACTION_EXIT.equals(action)) {
if(mp.isPlaying())mp.stop();
mp.release();
}

return super.onStartCommand(intent, flags, startId);

}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onPrepared(android.media.MediaPlayer mp) {

mp.start();
}

@Override
public void onDestroy() {
super.onDestroy();
//释放MediaPlayer的锁
lock.release();
}
}


XML文件

<RelativeLayout 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: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="com.example.sevicesmediaplayer.MainActivity" >

<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/button1"
android:layout_centerHorizontal="true"
android:text="play"
android:onClick="play"/>

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/button1"
android:layout_below="@+id/button1"
android:layout_marginTop="89dp"
android:text="pause"
android:onClick="pause"/>

<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button2"
android:layout_alignParentBottom="true"
android:layout_marginBottom="102dp"
android:text="exit"
android:onClick="exit"/>

</RelativeLayout>


注册服务

<service android:name=".MusicService"
android:process=":music">

<intent-filter >
<action android:name="com.music.ACTION_PLAY"/>
<action android:name="com.music.ACTION_PAUSE"/>
<action android:name="com.music.ACTION_EXIT"/>
</intent-filter>

</service>


添加加锁权限

<uses-permission android:name="android.permission.WAKE_LOCK"/>


作为前台运行

前台服务是哪些被认为用户知道的并且在内存低的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,他被放到了“正在进行中(Ongoing)”标题之下,这就意味着直到这个服务被终止或从前台删除通知才能被解除。

例如,一个播放音乐的音乐播放器服务应该被设置在前台运行,因为用户明确的知道它们的操作。状态栏中的通知可能指明了当前的歌曲,并且用户启动一个跟这个音乐播放器交互的Activity。

//发送作为前台通知的方法
private void nitification() {
//发送一个通知

Notification.Builder builder=new Notification.Builder(this);
builder.setTicker("我的第一个音乐播放器");
builder.setSmallIcon(R.id.action_settings);
builder.setContentInfo("正在播放");
builder.setContentTitle("音乐播放器");

Intent intent=new Intent(this,MainActivity.class);
PendingIntent pi=PendingIntent.getActivity(this,0, intent,PendingIntent.FLAG_UPDATE_CURRENT);

builder.setContentIntent(pi);

NotificationManager nm=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

Notification notifi=builder.build();
//设置为前台通知!!!
startForeground(0, notifi);
//发送通知
nm.notify(0,notifi);
}


处理音频焦点

简介

在给定的时间尽管只有一个活动可以运行,但Android是一个多任务环境。这对应用程序使用音频造成了一个特别大的难度,由于只有一个音频输出,可能会有好几个媒体服务争夺使用它。

Android 2.2之前,没有内置机制来解决这个问题,这可能在某些情况下导致糟糕的用户体验。例如,一个用户正在听音乐,同时另一个应用程序有很重要的事需要通知用户,由于吵闹的音乐用户可能不会听到提示音。从Android 2.2开始,Android平台为应用程序提供了一个方式来协商设备的音频输出,这个机制被称为音频焦点。

当您的应用程序需要输出音频,如音乐或一个通知,这时你就必须请求音频焦点。一旦得到焦点,它就可以自由的使用声音输出设备,同时它会不断监听焦点的更改。如果它被通知已经失去了音频焦点,它会要么立即杀死音频或立即降低到一个安静的水平(被称为“ducking”——有一个标记,指示哪一个是适当的)当它再次接收焦点时,继续不断播放。

音频焦点是自然的合作,应用程序都期望(强烈鼓励)遵守音频焦点指南,但规则并不是系统强制执行的。如果应用程序失去音频焦点后想要播放嘈杂的音乐,在系统中没有什么会阻止他。然而,这样可能会让用户有更糟糕的体验,并可能卸载这运行不当的应用程序。

请求音频焦点,您必须从AudioManager调用requestAudioFocus()方法

使用ContentResolver检索本地歌曲

public void showMusiclist(View v){
ContentResolver cr=getContentResolver();

Cursor c=cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null, null, null, null);
if(c!=null) {
while(c.moveToNext()) {
String musicPath=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DATA));
String musicName=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
String artist=c.getString(c.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String duration=c.getString(c.getColumnIndex(MediaStore.Audio.Media.DURATION));
System.out.println("路径"+musicPath);
System.out.println("歌名"+musicName);
System.out.println("歌手"+artist);
System.out.println("时常/毫秒:"+artist);
System.out.println("----------------------");

}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐