获取手机音乐的信息


1. 先在布局文件中添加一个ListView

<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/list_pressed"
android:dividerHeight="1px"
android:listSelector="@android:color/transparent"
android:id="@+id/listview">


2. 在fragment中初始化这个ListView



private ListView listView;

listView = (ListView) view.findViewById(R.id.listview);




3. 创建一个用于设置数据的adapter



public class AudioListAdapter extends CursorAdapter{

public AudioListAdapter(Context context, Cursor c) {
super(context, c);
}

//设置需要显示的布局文件
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return null;
}

//设置相关的数据的显示
@Override
public void bindView(View view, Context context, Cursor cursor) {

}
}


4. 优化adapter并为其设置数据的显示

4.1 创建一个viewHolder




class ViewHolder{
//这里是用于显示相关歌曲的名称与艺术家名称的控件,
TextView mTitleTextView,mArtistTextView;

public ViewHolder(View view)
{
mTitleTextView = (TextView) view.findViewById(R.id.tv_title);
mArtistTextView = (TextView) view.findViewById(R.id.tv_artist);
}



4.2 创建一个方法用于获取上面的viewHolder



private ViewHolder getHolder(View view)
{
ViewHolder viewHolder = (ViewHolder) view.getTag();
if(viewHolder==null)
{
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}
return viewHolder;
}

4.3 在adapter中使用viewHolder




public class AudioListAdapter extends CursorAdapter
{

public AudioListAdapter(Context context, Cursor c) {
super(context, c);
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent)
{
//设置显示音乐信息的列表内容
return View.inflate(context, R.layout.adapter_audio_list, null);
}
ViewHolder holder;
@Override
public void bindView(View view, Context context, Cursor cursor)
{
holder = getHolder(view);

//这里是通过对象保存数据的方式将cursor中的数据取出并设置相关显示
AudioItem audioItem = AudioItem.fromCursor(cursor);
holder.mTitleTextView.setText(StringUtil.formatAudioName(audioItem.getTitle()));
holder.mArtistTextView.setText(audioItem.getArtist());
}
}


4.4 这里是使用的对象保存数据的方法





public class AudioItem implements Serializable
{
private String title;
private String artist;
private String path;
private long duration;

//将cursor的数据封装于对象
public static AudioItem fromCursor(Cursor cursor){
AudioItem audioItem = new AudioItem();
audioItem.setArtist(cursor.getString(cursor.getColumnIndex(Media.ARTIST)));
audioItem.setDuration(cursor.getLong(cursor.getColumnIndex(Media.DURATION)));
audioItem.setPath(cursor.getString(cursor.getColumnIndex(Media.DATA)));
audioItem.setTitle(cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME)));
return audioItem;
}

public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
}


5 在fragment中初使化adapter并使用这个adapter





private AudioListAdapter mAudioAdapter;

mAudioAdapter = new AudioListAdapter(getActivity(), null);


6 将adapter设置给ListView




listView.setAdapter(adapter);


7 查询数据并将数据传输给mAudioAdapter




private SimpleQueryHandler queryHandler;

queryHandler = new SimpleQueryHandler(getActivity().getContentResolver());
//查询的音乐相关的信息
String[] projection = {Media._ID,Media.DISPLAY_NAME,Media.ARTIST,Media.DATA,Media.DURATION};
//数据查询
queryHandler.startQuery(0, adapter, Media.EXTERNAL_CONTENT_URI, projection, null, null, null);


8 使用到的相关查询辅助类




public class SimpleQueryHandler  extends AsyncQueryHandler{

public SimpleQueryHandler(ContentResolver cr) {
super(cr);
}
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
super.onQueryComplete(token, cookie, cursor);

if(cookie!=null && cookie instanceof CursorAdapter){
CursorAdapter adapter = (CursorAdapter) cookie;
adapter.changeCursor(cursor);//相当于notify
}
}
}







走到这里,我们就可以将手机中的音乐相关信息显示加载出来了














2 播放音乐的操作











9 创建用于播放音乐的显示页面(这里使用一个activity来显示)











public class AudioPlayerActivity extends  Activity{


}


在这里设置自定的播放音乐的显示页面








10 在AudioPlayerActivity的onCreate方法中获取传递的数据









//当前点击要播放的位置
int currentPosition = getIntent().getExtras().getInt("currentPosition");

//所有音乐信息的集合
ArrayList<AudioItem> audioList = (ArrayList<AudioItem>) getIntent().getExtras().getSerializable("audioList");








11 这里使用的是后台可以进行音乐播放,那么就需要使用到与服务的交互











创建用于播放音乐的服务并进行清单文件中的注册







public class AudioPlayService extends Service{

private AudioServiceBinder audioServiceBinder;
@Override
public IBinder onBind(Intent intent) {
return audioServiceBinder;
}
}
@Override
public void onCreate() {
super.onCreate();
audioServiceBinder = new AudioServiceBinder();

}

//数据相关的绑定操作
public class AudioServiceBinder extends Binder{
}
}










12 在播放音乐的activity中开启服务








AudioPlayerActivity的onCreate方法中







Intent intent = new Intent(this,AudioPlayService.class);
Bundle bundle = new Bundle();

//传输的数据
int currentPosition = getIntent().getExtras().getInt("currentPosition");
ArrayList<AudioItem> audioList = (ArrayList<AudioItem>) getIntent().getExtras().getSerializable("audioList");
//数据封装
bundle.putInt("currentPosition", currentPosition);
bundle.putSerializable("audioList", audioList);
intent.putExtras(bundle);
//服务绑定

serviceConnection = new AudioServiceConnection();

bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);
startService(intent);//为了给service传递数据




使用到对象 serviceConnection,类似一个中间人对象,是实现ServiceConnection接口的










class AudioServiceConnection implements ServiceConnection{
//当服务连接的时候会调用这个方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {

}
//当服务断开时候会调用这个方法
@Override
public void onServiceDisconnected(ComponentName name) {

}
}





13 activity 与 service方法的交互




在activity中 通过 serviceConnection 来获取 服务 AudioPlayService 中的AudioServiceBinder


这样我们就可以通过AudioServiceBinder这个对象来进行activity与service中方法的交互










private AudioServiceBinder audioServiceBinder;

class AudioServiceConnection implements ServiceConnection{
//当服务连接的时候会调用这个方法,那么可以在这个方法中获取binder的对象(通过它来操作服务中的相关方法)
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
audioServiceBinder = (AudioServiceBinder) service;
}
//当服务断开时候会调用这个方法
@Override
public void onServiceDisconnected(ComponentName name) {

}
}










14 在service中进行播放音乐的操作















首先获取传递的数据 
复写service的方法 onStartCommand 来获取传递的数据
private int currentPosition;
private ArrayList<AudioItem> audioList;
private AudioServiceBinder audioServiceBinder ;

@Override
public void onCreate() {
super.onCreate();
audioServiceBinder = new AudioServiceBinder();

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

//获取数据
currentPosition = intent.getExtras().getInt("currentPosition");
audioList = (ArrayList<AudioItem>) intent.getExtras().getSerializable("audioList");
//设置音乐播放
audioServiceBinder.playAudio();

return START_STICKY;//如果服务被杀死,会自动重启
}

在AudioServiceBinder 中设置与播放音乐相关的操作逻辑
设置播放音乐的操作方法
public class AudioServiceBinder extends Binder{
/**
* 播放音乐
*/
public void playAudio(){
//判断一下是否有音乐资源
if(audioList==null || audioList.size()==0)return;
if(mediaPlayer!=null){
mediaPlayer.release();
mediaPlayer = null;
}

AudioItem audioItem = audioList.get(currentPosition);
//创建mediaPlayer对象
mediaPlayer = new MediaPlayer();
//设置相关的监听
mediaPlayer.setOnPreparedListener(mOnPreparedListener);
mediaPlayer.setOnCompletionListener(mOnCompletionListener);
//设置数据源
try {
mediaPlayer.setDataSource(audioItem.getPath());
mediaPlayer.prepareAsync();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//创建相关的加载播放监听 并设置音乐的播放

private OnPreparedListener mOnPreparedListener = new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mediaPlayer.start();

}
};

private OnCompletionListener mOnCompletionListener = new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {

}
};
}






15 在服务中通过发送广播通知Activity中更新页面显示数据



定义我们用到的广播接收者

class AudioServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

}
}


在activity的OnCreate方法中进行注册



/**
* 注册AudioService中的广播接受者
*/
private void registerAudioServiceReceiver() {
receiver = new AudioServiceReceiver();
IntentFilter filter = new IntentFilter(AudioPlayService.ACTION_NOTIFY_PREPARED);//参数是广播接收的标识
//filter.addAction(AudioPlayService.ACTION_COMPLATION); 这里可以添加多个活动
registerReceiver(receiver, filter);
}





在服务中,当音乐开始进行播放的时候,发送广播,并将音乐的信息发给activity中

private void notifyPrepared(){
Intent intent = new Intent(ACTION_NOTIFY_PREPARED);
intent.putExtra("audioItem", audioList.get(currentPosition));//这里面就是携带的数据
sendBroadcast(intent);
}





当广播发送后,我们在对应的广播接收者中进行消息的接收

class AudioServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (AudioPlayService.ACTION_NOTIFY_PREPARED.equarrayLists(intent.getAction())) {
AudioItem audioItem = (AudioItem) intent.getSeriarrayListizableExtra("audioItem");

} else if (AudioPlayService.ACTION_COMPLATION.equarrayLists(intent.getAction())) {
}
}
}