简单实现Android本地音乐的播放
2017-08-08 19:01
337 查看
首先整理一下思路,为了实现该功能,我们只需要主界面和音乐界面,外加一个广播接收者和service.这几个就构成了这个小项目的核心.
1主界面
在这个activity中,我们主要任务,就是为他注册一个广播接收者,让他实现广播的发送和接收,定义一个handler将他赋给广播接收者,使得能够进行同时对音乐播放的状态做处理.
2音乐界面
音乐界面的主体功能和MainActivity并没有太多的区别,也是注册一个广播接收者秉将handler对象赋给广播接收者来实现数据的传输.但是在这个基础上定义了歌单列表和一个自定义控件来实现音乐播放的频谱数据采集
3 广播接收者
讲对广播的注册方法也放进了广播接收者本身,使得在创建广播接收者对象的时候可以方便的调用注册和注销.将对接收到的广播放在onReceive中进行处理并进行对应的消息转发
4 service
对音乐进行实际操作的对象,接收从广播接收者那里进过处理的数据,然后进行对应的操作,并且定时通过广播发送歌曲信息,使界面信息与实际播放信息实时更新
5自定义控件
该自定义工具用来实现频谱绘制,因为将该大小设置为全屏,因此只需要重写onDraw方法就好.定义一个点击事件,通过点击实现三种频谱图的切换.
6获取设备外部SD卡的歌曲信息的工具类
这个类用来拿到SD存放的音频文件,手机内部存储的应该拿不到(因为我没拿到.)具体方法的分析
7 自定义的歌曲对象
8 静态全局变量类
9 xml文件
main界面的
music界面
music的列表界面
通用的 点击停止 播放下一首 上一首 按键布局
1主界面
public class MainActivity extends AppCompatActivity { TopBar mTopBar; private boolean isUpdate = true;//是否更新界面 private TextView txtSongname; private AudioManager audioManager;//音频管理器 private boolean isMusicPlaying = false; private String MusicOperateAction = StaticValues.MusicOperateAction; private String MusicOperateData = StaticValues.MusicOperateData; private MusicBroadcast musicBroadCast; private ImageView imgvPre, imgvPauseStart, imgvNext, imgvPlus, imgvMinus; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == StaticValues.MUSIC_PROGRESS_UPDATE) { String[] allDatas = msg.obj.toString().trim().split(","); if (allDatas.length == 5 && isUpdate) updateMusicControls(allDatas); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 监听广播 musicBroadCast = new MusicBroadcast(MainActivity.this, handler); musicBroadCast.registReceiver(); audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); txtSongname = (TextView) this.findViewById(R.id.txt_songname); txtSongname.setOnClickListener(ocltwo); imgvPre = (ImageView) this.findViewById(R.id.imgv_pre); imgvPre.setOnClickListener(ocl); imgvPauseStart = (ImageView) this.findViewById(R.id.imgv_pause_start); imgvPauseStart.setOnClickListener(oclthree); imgvNext = (ImageView) this.findViewById(R.id.imgv_next); imgvNext.setOnClickListener(ocl); imgvPlus = (ImageView) this.findViewById(R.id.imgv_plus); imgvPlus.setOnClickListener(ocltwo); imgvMinus = (ImageView) this.findViewById(R.id.imgv_minus); imgvMinus.setOnClickListener(ocltwo); } private void updateMusicControls(String[] allDatas) { String titleStr = allDatas[0]; String isPlayTxt = allDatas[4]; if (!titleStr.equals(txtSongname.getText())) txtSongname.setText(titleStr); if (isPlayTxt.equals("1")) { if (!isMusicPlaying) { isMusicPlaying = true; imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_pause1)); } }else { if (isMusicPlaying) { isMusicPlaying = false; imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_play1)); } } } /** * 控制播放上一首,下一首 */ View.OnClickListener ocl = new View.OnClickListener() { @Override public void onClick(View v) { String str = ""; Intent intent = new Intent(StaticValues.MusicOperateAction); switch (v.getId()) { case R.id.imgv_pre: str = StaticValues.MUSIC_PRE + "," + 0; break; case R.id.imgv_next: str = StaticValues.MUSIC_NEXT + "," + 0; break; } intent.putExtra(MusicOperateData, str); sendBroadcast(intent); } }; /** * 控制音量打下以及跳转到专门的音乐界面 */ View.OnClickListener ocltwo = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.imgv_plus: audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); break; case R.id.imgv_minus: audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,AudioManager.ADJUST_LOWER,AudioManager.FLAG_SHOW_UI); break; case R.id.txt_songname: Intent intent=new Intent(MainActivity.this,MusicActivity.class); startActivity(intent); break; } } }; View.OnClickListener oclthree=new View.OnClickListener() { @Override public void onClick(View v) { String str = ""; Intent intent = new Intent(MusicOperateAction); switch (v.getId()) { case R.id.imgv_pause_start: if (isMusicPlaying) { isMusicPlaying = false; imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_play1)); } else { isMusicPlaying = true; imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_pause1)); } str = StaticValues.MUSIC_START_OR_PAUSE + "," + 0; break; } intent.putExtra(MusicOperateData, str); sendBroadcast(intent); } }; }
在这个activity中,我们主要任务,就是为他注册一个广播接收者,让他实现广播的发送和接收,定义一个handler将他赋给广播接收者,使得能够进行同时对音乐播放的状态做处理.
2音乐界面
public class MusicActivity extends AppCompatActivity { private Visualizer visualizer;//定义示波器 private MusicBroadcast musicBroadCast = null; private LinearLayout lin_back; private MyVisualizerView viewSpectrum; private ListView listView; private ImageView imgvPre, imgvPauseStart, imgvNext, imgvPlus, imgvMinus; private TextView txtTitle, txtAlbum, txtPresentTime, txtAllTime, txtPrompt; private SeekBar seekBar; private AudioManager audioManager; private boolean isPlaying = false; private String MusicOperateAction = StaticValues.MusicOperateAction; private String MusicOperateData = StaticValues.MusicOperateData; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == StaticValues.MUSIC_PROGRESS_UPDATE) { String[] allDatas = msg.obj.toString().trim().split(","); if (allDatas.length == 5) updateMusicControls(allDatas); } } }; /** * 更新控件 * * @param allDatas */ private void updateMusicControls(String[] allDatas) { String titleStr = allDatas[0]; String albumStr = allDatas[1]; String presentTimeStr = getFormatedDateTime("mm:ss", Integer.parseInt(allDatas[2])) + ""; String allTimeStr = getFormatedDateTime("mm:ss", Integer.parseInt(allDatas[3])) + ""; String isPlayTxt = allDatas[4]; if (!titleStr.equals(txtTitle.getText())) txtTitle.setText(titleStr); if (!albumStr.equals(txtAlbum.getText())) txtAlbum.setText(albumStr); if (!allTimeStr.equals(txtAllTime.getText())) txtAllTime.setText(allTimeStr); if (seekBar.getMax() != Integer.parseInt(allDatas[3])) seekBar.setMax(Integer.parseInt(allDatas[3])); if (!presentTimeStr.equals(txtPresentTime.getText())) { txtPresentTime.setText(presentTimeStr); seekBar.setProgress(Integer.parseInt(allDatas[2])); } if (isPlayTxt.equals("1")) { if (!isPlaying) { isPlaying = true; visualizer.setEnabled(true); imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_pause1)); } } else { if (isPlaying) { isPlaying = false; visualizer.setEnabled(false); imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_play1)); } } } private String getFormatedDateTime(String pattern, long dateTime) { SimpleDateFormat sDateFormat = new SimpleDateFormat(pattern); return sDateFormat.format(new Date(dateTime + 0)); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music); initView(); musicBroadCast = new MusicBroadcast(MusicActivity.this, handler); musicBroadCast.registReceiver(); show(); } /** * 显示歌曲的ListView初始化*/ private void show() { MyApplication myApplication= (MyApplication) getApplication(); final List<Song>songs=myApplication.getSongs(); if (songs!=null&&songs.size()>0){ List<HashMap<String,Object>>data=new ArrayList<>(); for (Song song:songs){ HashMap<String,Object>map=new HashMap<>(); map.put("title",song.getTitle()); map.put("duration",getFormatedDateTime("mm:ss",song.getDuration())); map.put("singer",song.getSinger()); data.add(map); } SimpleAdapter adapter=new SimpleAdapter(MusicActivity.this,data,R.layout.music_item, new String[]{"title", "duration", "singer"}, new int[]{R.id.txt_title, R.id.txt_duration, R.id.txt_singer}); listView.setAdapter(adapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent intent=new Intent(StaticValues.MusicOperateAction); String str=StaticValues.MUSIC_PLAY+","+position; intent.putExtra(StaticValues.MusicOperateData,str); sendBroadcast(intent); txtTitle.setText(songs.get(position).getTitle()); txtAlbum.setText(songs.get(position).getAlbum()); txtAllTime.setText(getFormatedDateTime("mm:ss",songs.get(position).getDuration())); } }); }else { listView.setVisibility(View.GONE); txtPrompt.setVisibility(View.VISIBLE); } } private void initView() { audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE); listView = (ListView) this.findViewById(R.id.list_music); txtPrompt = (TextView) this.findViewById(R.id.txt_prompt); txtTitle = (TextView) this.findViewById(R.id.txt_title); txtAlbum = (TextView) this.findViewById(R.id.txt_album); txtPresentTime = (TextView) this.findViewById(R.id.txt_present_time); txtAllTime = (TextView) this.findViewById(R.id.txt_all_time); seekBar = (SeekBar) this.findViewById(R.id.sb_music); seekBar.setOnSeekBarChangeListener(seekBarChange); imgvPre = (ImageView) this.findViewById(R.id.imgv_pre); imgvPre.setOnClickListener(ocl); imgvPauseStart = (ImageView) this.findViewById(R.id.imgv_pause_start); imgvPauseStart.setOnClickListener(oclthree); imgvNext = (ImageView) this.findViewById(R.id.imgv_next); imgvNext.setOnClickListener(ocl); imgvPlus = (ImageView) this.findViewById(R.id.imgv_plus); imgvPlus.setOnClickListener(ocltwo); imgvMinus = (ImageView) this.findViewById(R.id.imgv_minus); imgvMinus.setOnClickListener(ocltwo); viewSpectrum = (MyVisualizerView) this.findViewById(R.id.view_spectrum); setUpVisualizer(); } /** * 频谱数据采集 */ private void setUpVisualizer() { MyApplication myApplication = (MyApplication) getApplication(); visualizer = new Visualizer(myApplication.getMediaObject()); visualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]); visualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { @Override public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, int i) { Log.i("AAA", "bytes:" + bytes.length); viewSpectrum.updateVisualizer(bytes); } @Override public void onFftDataCapture(Visualizer visualizer, byte[] bytes, int i) { } }, Visualizer.getMaxCaptureRate() / 2, true, false); visualizer.setEnabled(false);//数据采样 } SeekBar.OnSeekBarChangeListener seekBarChange = new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { Intent intent = new Intent(StaticValues.MusicOperateAction); String str = StaticValues.MUSIC_SEEK + "," + progress; intent.putExtra(StaticValues.MusicOperateData, str); sendBroadcast(intent); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }; View.OnClickListener ocl = new View.OnClickListener() { @Override public void onClick(View v) { String str = ""; Intent intent = new Intent(StaticValues.MusicOperateAction); switch (v.getId()) { case R.id.imgv_pre: str = StaticValues.MUSIC_PRE + "," + 0; visualizer.setEnabled(true); break; case R.id.imgv_next: str = StaticValues.MUSIC_NEXT + "," + 0; visualizer.setEnabled(true); break; } intent.putExtra(StaticValues.MusicOperateData, str); sendBroadcast(intent); } }; View.OnClickListener ocltwo = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { case R.id.imgv_plus: audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); break; case R.id.imgv_minus: audioManager.adjustStreamVolume(AudioManager.STREAM_MU 1a9b7 SIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI); break; } } }; View.OnClickListener oclthree = new View.OnClickListener() { @Override public void onClick(View v) { String str = ""; Intent intent = new Intent(StaticValues.MusicOperateAction); if (isPlaying) { isPlaying = false; visualizer.setEnabled(false); imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_play1)); } else { isPlaying = true; visualizer.setEnabled(true); imgvPauseStart.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.icon_music_circle_pause1)); } str = StaticValues.MUSIC_START_OR_PAUSE + "," + 0; intent.putExtra(MusicOperateData, str); sendBroadcast(intent); } }; @Override protected void onDestroy() { super.onDestroy(); visualizer.setEnabled(false); visualizer.release(); musicBroadCast.unRegistReceiver(); } }
音乐界面的主体功能和MainActivity并没有太多的区别,也是注册一个广播接收者秉将handler对象赋给广播接收者来实现数据的传输.但是在这个基础上定义了歌单列表和一个自定义控件来实现音乐播放的频谱数据采集
3 广播接收者
public class MusicBroadcast extends BroadcastReceiver { private Context mContext; private Handler mHandler; private IntentFilter filter = new IntentFilter(); private String MusicOperateAction = StaticValues.MusicOperateAction; private String ProgressUpdateAction = StaticValues.ProgressUpdateAction; public MusicBroadcast(Context context, Handler handler) { mContext = context; mHandler = handler; filter.addAction(MusicOperateAction); filter.addAction(ProgressUpdateAction); } public Intent registReceiver() { //把原始的注册方法封装进这,供其他地方调用 return mContext.registerReceiver(this, filter); } public void unRegistReceiver() { mContext.unregisterReceiver(this); } @Override public void onReceive(Context context, Intent intent) { if (mHandler == null) return; String action = intent.getAction(); Message msg = new Message(); if (action.equals(MusicOperateAction)) { String str = intent.getStringExtra(StaticValues.MusicOperateData); msg.what = StaticValues.MUSIC_OPERATE; msg.obj = str; } else if (action.equals(ProgressUpdateAction)) { String str = intent.getStringExtra(StaticValues.UIUpdateData); msg.what = StaticValues.MUSIC_PROGRESS_UPDATE; msg.obj = str; } mHandler.sendMessage(msg); } }
讲对广播的注册方法也放进了广播接收者本身,使得在创建广播接收者对象的时候可以方便的调用注册和注销.将对接收到的广播放在onReceive中进行处理并进行对应的消息转发
4 service
public class MusicService extends Service { private MyApplication myApplication = null; private MusicBroadcast musicBroadCast = null; private MediaPlayer myPlayer; private int musicIndex = 0; private int musicMax = 0; private String songName = "", albumName = ""; private int presentTime = 0, allTime = 0; private String isPlay = "0";//0:停止,1:播放 private List<Song> songs = null; private Timer timerMusic;//定时线程 /** * 进行对音乐播放的实际操作 */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == StaticValues.MUSIC_OPERATE) { String[] datas = msg.obj.toString().split(","); String a=datas[0]; int info = Integer.parseInt(datas[0]); if (info == StaticValues.MUSIC_PLAY) { musicIndex = Integer.parseInt(datas[1]); playMusic(); } else if (info == StaticValues.MUSIC_START_OR_PAUSE) { playOrPauseMusic(); } else if (info == StaticValues.MUSIC_PRE) { preMusic(); } else if (info == StaticValues.MUSIC_NEXT) { nextMusic(); } else if (info == StaticValues.MUSIC_STOP) { stopMusic(); } else if (info == StaticValues.MUSIC_SEEK) { seekTo(Integer.parseInt(datas[1])); } } } }; public MusicService() { myPlayer = new MediaPlayer(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); musicBroadCast = new MusicBroadcast(MusicService.this, handler); musicBroadCast.registReceiver(); myApplication = (MyApplication) getApplication(); myApplication.setMediaObject(myPlayer.getAudioSessionId()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { songs = AudioUtils.getAllSongs(MusicService.this); if (songs != null && songs.size() > 0) { musicMax = songs.size(); myApplication.setSongs(songs); playMusic(); playOrPauseMusic(); } timerMusic = new Timer(); timerMusic.schedule(new TimerTask() { @Override public void run() { sendSongData(); } }, 0, 1000); return super.onStartCommand(intent, flags, startId); } /** * 发送歌曲数据 */ private void sendSongData() { try { if (songs != null && songs.size() > 0 && myPlayer != null) { presentTime = myPlayer.getCurrentPosition();//获取当前播放进度 allTime = songs.get(musicIndex).getDuration();//获取当前播放歌曲的总时长 songName = songs.get(musicIndex).getTitle(); albumName = songs.get(musicIndex).getAlbum();//获取专辑名 if (myPlayer.isPlaying()) isPlay = "1"; else isPlay = "0"; String allData = songName + ",——" + albumName + "——," + presentTime + "," + allTime + "," + isPlay; Intent intent = new Intent(StaticValues.ProgressUpdateAction); intent.putExtra(StaticValues.UIUpdateData, allData); sendBroadcast(intent); } } catch (Exception e) { } } /** * 设置当前播放点 */ private void seekTo(int position) { if (myPlayer != null) { myPlayer.seekTo(position); } } /** * 停止播放音乐 */ private void stopMusic() { try { if (songs != null && songs.size() > 0 && myPlayer != null) { myPlayer.stop(); } } catch (Exception e) { } } private void nextMusic() { try { if (songs != null && songs.size() > 0 && myPlayer != null) { stopMusic(); if (musicIndex < musicMax - 1) { musicIndex++; } else { musicIndex = 0; } playMusic(); } } catch (Exception e) { e.printStackTrace(); } } private void preMusic() { try { if (songs != null && songs.size() > 0 && myPlayer != null) { stopMusic(); if (musicIndex > 0) { musicIndex--; } else { musicIndex = musicMax - 1; } playMusic(); } } catch (Exception e) { e.printStackTrace(); } } /** * 暂停或开始播放音乐 */ private void playOrPauseMusic() { try { if (myPlayer.isPlaying()) { myPlayer.pause(); } else { myPlayer.start(); } } catch (Exception e) { e.printStackTrace(); } } private void playMusic() { try { if (songs != null && songs.size() > 0 && myPlayer != null) { songs = myApplication.getSongs(); myPlayer.reset();//重新设置要播放的音乐 myPlayer.setDataSource(songs.get(musicIndex).getFileUrl()); myPlayer.prepare();//预加载音频 myPlayer.seekTo(0); myPlayer.start(); myPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { nextMusic(); } }); } } catch (Exception e) { e.printStackTrace(); } } /** * 更新播放列表 */ public void updateMusicData() { stopMusic(); songs = myApplication.getSongs(); musicMax = songs.size(); musicIndex = 0; } @Override public void onDestroy() { super.onDestroy(); try { if (timerMusic != null) { timerMusic.cancel(); timerMusic = null; } musicBroadCast.unRegistReceiver(); stopMusic(); myPlayer = null; } catch (Exception e) { e.printStackTrace(); } } }
对音乐进行实际操作的对象,接收从广播接收者那里进过处理的数据,然后进行对应的操作,并且定时通过广播发送歌曲信息,使界面信息与实际播放信息实时更新
5自定义控件
public class MyVisualizerView extends View { private byte[] bytes; private float[] points; private Paint paint = new Paint(); private Rect rect = new Rect(); private byte type = 1; public MyVisualizerView(Context context) { super(context); init(); } public MyVisualizerView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { bytes = null; paint.setStrokeWidth(1F); paint.setAntiAlias(true); paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.FILL); } public void updateVisualizer(byte[] ftt) { bytes = ftt; //通知组件重绘 invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { //当触碰该组件时,切换波形类型 if (event.getAction() != MotionEvent.ACTION_DOWN) { return false; } type++; if (type >= 3) { type = 0; } return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bytes == null) return; //绘制白色背景 canvas.drawColor(Color.WHITE); //记录组件的宽高 rect.set(0, 0, getWidth(), getHeight()); switch (type) { case 0: //绘制块型波形图 for (int i = 0; i < bytes.length - 1; i++) { float left = getWidth() * i / (bytes.length - 1); float top = rect.height() - (byte) (bytes[i + 1] + 128) * rect.height() / 128; float right = left + 1; float bottom = rect.height(); canvas.drawRect(left, top, right, bottom, paint); } break; case 1: //绘制柱型波形图 for (int i = 0; i < bytes.length - 1; i += 18) { float left = rect.width() * i / (bytes.length - 1); float top = rect.height() - (byte) (bytes[i + 1] + 128) * rect.height() / 128; float right = left + 6; float bottom = rect.height(); canvas.drawRect(left, top, right, bottom, paint); } break; case 2: //绘制曲线波形图 if (points == null || points.length < bytes.length * 4) { points = new float[bytes.length * 4]; } for (int i = 0; i < bytes.length - 1; i++) { points[i * 4] = rect.width() * i / (bytes.length - 1); points[i * 4 + 1] = (rect.height() / 2) + ((byte) (bytes[i] + 128)) * 128 / (rect.height() / 2); points[i * 4 + 2] = rect.width() * (i + 1) / (bytes.length - 1); points[i * 4 + 3] = (rect.height() / 2) + ((byte) (bytes[i + 1] + 128)) * 128 / (rect.height() / 2); } canvas.drawLines(points, paint); break; } } }
该自定义工具用来实现频谱绘制,因为将该大小设置为全屏,因此只需要重写onDraw方法就好.定义一个点击事件,通过点击实现三种频谱图的切换.
6获取设备外部SD卡的歌曲信息的工具类
public static ArrayList<Song> getAllSongs(Context context) { ArrayList<Song> songs = new ArrayList<>(); //Cursor是每行的集合,context.getContentResolver();查询媒体数据库 Cursor cursor = context.getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DURATION, //歌曲的歌手名MediaStore.Audio.Media.ARTIST MediaStore.Audio.Media.ARTIST, //歌曲的专辑名MediaStore.Audio.Media.ALBUM MediaStore.Audio.Media.ALBUM, MediaStore.Audio.Media.YEAR, MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.SIZE, //歌曲文件的路径MediaStore.Audio.Media.DATA MediaStore.Audio.Media.DATA}, MediaStore.Audio.Media.MIME_TYPE + "=? or " + MediaStore.Audio.Media.MIME_TYPE + "=?", new String[]{"audio/mpeg", "audio/x-ms-wma"}, null); if (cursor.moveToFirst()) { do { Song song = new Song(); // 文件名 song.setFileName(cursor.getString(1)); // 歌曲名 song.setTitle(cursor.getString(2)); // 时长 song.setDuration(cursor.getInt(3)); // 歌手名 song.setSinger(cursor.getString(4)); // 专辑名 song.setAlbum(cursor.getString(5)); // 年代 if (cursor.getString(6) != null) { song.setYear(cursor.getString(6)); } else { song.setYear("未知"); } // 歌曲格式 if ("audio/mpeg".equals(cursor.getString(7).trim())) { song.setType("mp3"); } else if ("audio/x-ms-wma".equals(cursor.getString(7).trim())) { song.setType("wma"); } // 文件大小 if (cursor.getString(8) != null) { float size = cursor.getInt(8) / 1024f / 1024f; song.setSize((size + "").substring(0, 4) + "M"); } else { song.setSize("未知"); } // 文件路径 if (cursor.getString(9) != null) { song.setFileUrl(cursor.getString(9)); } songs.add(song); } while (cursor.moveToNext()); cursor.close(); } return songs; } }
这个类用来拿到SD存放的音频文件,手机内部存储的应该拿不到(因为我没拿到.)具体方法的分析
7 自定义的歌曲对象
public class Song { private String fileName;// 文件名 private String title;// 歌曲名 private int duration;// 时长 private String singer;// 歌手名 private String album;// 专辑名 private String year;// 年代 private String type;//歌曲格式 private String size;// 文件大小 private String fileUrl;// 文件路径 public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; } public String getSinger() { return singer; } public void setSinger(String singer) { this.singer = singer; } public String getAlbum() { return album; } public void setAlbum(String album) { this.album = album; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } public String getFileUrl() { return fileUrl; } public void setFileUrl(String fileUrl) { this.fileUrl = fileUrl; } }
8 静态全局变量类
public class StaticValues { public static final String MusicOperateAction = "android.hardware.action.MUSIC_OPERATE_ACTION";// 音乐相关操作广播标示 public static final String ProgressUpdateAction = "android.hardware.action.PROGRESS_UPDATE_ACTION";// 音乐UI界面相关进度更新广播标示 public static final int MUSIC_OPERATE = 0X10001;//音乐播放相关操作 public static final int MUSIC_PROGRESS_UPDATE = 0X10003;//音乐界面进度更新 public static final String UIUpdateData = "UIUPDATEDATA";//音乐UI界面更新相关信息标示 public static final int MUSIC_START_OR_PAUSE = 0X00001;//音乐开始或者暂停播放 public static final int MUSIC_STOP = 0X00002;//音乐停止播放 public static final int MUSIC_NEXT = 0X00003;//下一首音乐 public static final int MUSIC_PRE = 0X00004;//上一首音乐 public static final int MUSIC_PLAY = 0X00005;//指定音乐播放 public static final int MUSIC_SEEK = 0X00006;//指定音乐进度 public static final String MusicOperateData = "MUSICOPERATEDATA";//音乐操作相关信息标示 }
9 xml文件
main界面的
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" 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="m520it.com.mselfview.MainActivity" android:orientation="vertical"> <!-- <m520it.com.mselfview.myView.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!"/>--> <!-- <m520it.com.mselfview.myView.TopBar android:id="@+id/tb" android:layout_width="match_parent" android:layout_height="wrap_content" app:leftBackground="#ffffff" app:leftText="左边" app:leftTextColor="#111122" app:rightBackground="#449988" app:rightText="右边" app:rightTextColor="#887898" app:title="自定义咯" app:titleTextColor="#666666ff" app:titleTextSize="18sp"/>--> <!-- <m520it.com.mselfview.myView.AudioView android:layout_width="match_parent" android:layout_height="match_parent"> </m520it.com.mselfview.myView.AudioView>--> <TextView android:id="@+id/txt_songname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_marginTop="20dp" android:maxLines="1" android:text="歌曲名" android:textSize="25sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp"> <include layout="@layout/music_interface" /> </LinearLayout> </LinearLayout>
music界面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="20dp" android:layout_marginLeft="20dp" android:layout_marginRight="10dp" android:layout_marginTop="20dp" android:layout_weight="2" android:orientation="vertical"> <ListView android:id="@+id/list_music" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:divider="#00ffffff" android:dividerHeight="6dp" /> <TextView android:id="@+id/txt_prompt" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/grey_gridlines" android:gravity="center" android:text="不存在音乐" android:textSize="25sp" android:visibility="gone" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="20dp" android:layout_marginLeft="10dp" android:layout_marginRight="20dp" android:layout_marginTop="20dp" android:layout_weight="1" android:background="@drawable/grey_gridlines" android:orientation="vertical"> <TextView android:id="@+id/txt_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="歌曲名" android:textColor="#7cce7a" android:textSize="25sp" /> <TextView android:id="@+id/txt_album" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="专辑" android:textColor="#7cce7a" android:textSize="20sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"> <m520it.com.mselfview.MusicMedial.MyVisualizerView android:id="@+id/view_spectrum" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="3dp" android:background="#337cce7a" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <TextView android:id="@+id/txt_present_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" android:textColor="#7cce7a" /> <SeekBar android:id="@+id/sb_music" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_weight="1" /> <TextView android:id="@+id/txt_all_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="00:00" android:textColor="#7cce7a" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp"> <include layout="@layout/music_interface" /> </LinearLayout> </LinearLayout> </LinearLayout> </LinearLayout>
music的列表界面
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/grey_gridlines" android:orientation="vertical"> <TextView android:id="@+id/txt_title" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"> <TextView android:id="@+id/txt_singer" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1"> <TextView android:id="@+id/txt_duration" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> </LinearLayout>
通用的 点击停止 播放下一首 上一首 按键布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <ImageView android:id="@+id/imgv_plus" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginLeft="20dp" android:src="@drawable/icon_volume_plus_img" /> <ImageView android:id="@+id/imgv_pre" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginLeft="20dp" android:src="@drawable/icon_up_music_img" /> <ImageView android:id="@+id/imgv_pause_start" android:layout_width="72dp" android:layout_height="72dp" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:src="@drawable/icon_music_circle_play1" /> <ImageView android:id="@+id/imgv_next" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginRight="20dp" android:src="@drawable/icon_down_music_img" /> <ImageView android:id="@+id/imgv_minus" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginRight="20dp" android:src="@drawable/icon_volume_minus_img" /> </LinearLayout>
相关文章推荐
- android音乐播放简单实现的简单示例(MediaPlayer)
- Android用MediaPlay方法实现本地音乐的播放,与进度条的实现
- Android开发本地及网络Mp3音乐播放器(六)实现独立音乐播放界面
- Android实现本地音乐播放(一、实现音频的读取)
- android 简单的音乐播放实现
- 【Android】Android开发实现进度条效果,SeekBar的简单使用。音量,音乐播放进度,视频播放进度等
- Android--MediaPlayer(实现列表选歌,上一首,下一首,清空播放列表,搜索本地音乐文件)
- Android--MediaPlayer(实现列表选歌,上一首,下一首,清空播放列表,搜索本地音乐文件)
- Android-服务与广播接收者实现本地音乐播放
- Android开发本地及网络Mp3音乐播放器(六)实现独立音乐播放界面
- Android--MediaPlayer(实现列表选歌,上一首,下一首,清空播放列表,搜索本地音乐文件)
- Android使用本地Service实现后台播放音乐
- Android开发本地及网络Mp3音乐播放器(四)实现音乐播放
- Android通过Service实现简单的音乐播放
- Android使用Service实现简单音乐播放实例
- Android实现简单音乐播放控件
- Android开发本地及网络Mp3音乐播放器(四)实现音乐播放
- Android MediaPlayer实现音乐播放一--简单播放
- [置顶] 【Android】Android开发实现进度条效果,SeekBar的简单使用。音量,音乐播放进度,视频播放进度等
- 简单音乐播放实例的实现,Android Service AIDL 远程调用服务