Android音乐播放器高级开发



获取手机音乐的信息


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())) {
			}
		}
	}








早起的年轻人 CSDN认证博客专家 移动开发 项目管理 Java
只要用心去做,每一件事情还是有可能成功的,当然成功是没有界限的,只不过是达到自己心里的那个目标,公众号:我的大前端生涯,一个爱喝茶的程序员,通常会搞搞SpringBoot 、Herbinate、Mybatiys、Android、iOS、Flutter、Vue、小程序等.
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页