Android 酷炫来袭:制作属于你自己的音频播放器(综合运用MediaPlayer、Service、Broadcast、ListView、SeekBar)
来源:互联网 发布:淘宝行业数据哪里看 编辑:程序博客网 时间:2024/06/06 21:22
今天制作了一个属于自己的音乐播放器感觉还不错,分享出来,希望能够帮助大家。感觉知识点挺多的,也挺使用的,大大提高了个人兴趣,哈哈,我是程序员啊程序员。
为了有所侧重,我将注意点和学习点放在文章的最开篇。
一、学习重点与注意点
1、Mediaplayer的生命周期、相关方法及其使用
2、如何自定义SeekBar
3、接收广播的动态注册与注销
4、获取文件路径
5、获取歌曲的名称、作者名、图片
6、Service服务的使用
二、Mediaplayer介绍
想要制作一个属于自己的风格样式的音乐播放器,首先我们要学会使用音乐播放器。
Mediaplayer的生命周期
具体的查看API,这里附一张生命周期图。
Mediaplayer的证明周期中我们可以看出,Mediaplayer开始的时候需要调用reset()方法,然后是setDataResource()-prepare()-start()在MediaPlayer开启之后,我们可以让它暂停和停止等操作。
reset():将Mediaplayer对象重置到刚刚创建的状态。
setDataResource():设置要播放的音频文件的位置。
prepare():在开始播放之前调用这个方法完成准备工作(使用之前需要设置prepare监听)。
start():开始或继续播放音频文件
seekTo():从指定位置开始播放
stop():停止播放音频。
getDuration():获取载入的音频文件的时长
getCurrentPosition():获取音频文件的当前播放位置
简单的使用方法
点击按钮设置音频播放
public class MainActivity extends Activity implements OnClickListener{ private Button mbtn_start; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mbtn_start=(Button) findViewById(R.id.bt_start); mbtn_start.setOnClickListener(this); //获取文件路径,如果我们不知道文件具体放在那里可以通过log打印出来 File musicDir=Environment.getExternalStorageDirectory(); Log.d("音乐", Environment.getExternalStorageDirectory().getAbsolutePath()); musicDir = new File(musicDir, "/musics"); Toast.makeText(getApplicationContext(), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath(), Toast.LENGTH_LONG).show(); File[] files=musicDir.listFiles();//获取所有的文件 for(File file:files){ Log.d("路径", file.getAbsolutePath()); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_start: //new 一个新Mediaplayer对象,按照生命周期顺序操作 MediaPlayer mediaplayer=new MediaPlayer(); mediaplayer.reset(); File musicDir=Environment.getExternalStorageDirectory(); File[] files=musicDir.listFiles();//获取所有的文件 for(File file:files){ Log.d("路径", file.getAbsolutePath()); } try { mediaplayer.setDataSource(files[23].getAbsolutePath()); mediaplayer.prepare(); //设置prepare监听器,查看是否准备好,可以开始? mediaplayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //准备好了之后开始播放 mp.start(); } }); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; default: break; } } }
注意:我们还需要在manifest中获取读sdcard的权限。
三、制作音频播放器
Ⅰ 开启音乐并使音乐能够在后台运行
1、制作布局,ListView(+子布局+Adapter)+SeekBar+TextView+ToggleButton
2、循序渐进:书写MusicService类继承Service (这里别忘记在manifest中注册),为了保证音乐能够在后台运行,在之后的步骤中我们将在MusicService中创建线程,开启音乐。
3、开启MusicService:在MainActivity中获得文件路径,通过Intent的putStringArrayListExtra的方法传递给MusicService,并监听listview的item点击事件找到要播放的文件的position传递给Service。
4、在MusicService中创建线程,开启音乐
①布局+ListView+子布局+Adapter
在布局中我们顺便学习一下自定义SeekBar样式
新建xml文件,设置点击图片
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:drawable="@drawable/list_btn_radio_check_on" android:state_focused="true" android:state_window_focused="true"></item> <item android:drawable="@drawable/list_btn_radio_check_on" android:state_selected="true" android:state_window_focused="true"></item> <item android:drawable="@drawable/list_btn_radio_check_on" android:state_pressed="true" android:state_window_focused="true"></item> <item android:drawable="@drawable/list_btn_radio_check_off" ></item></selector>
SeekBar引用(通过设置Thumb)
<SeekBar android:id="@+id/seekbar" android:layout_width="0dp" android:layout_height="wrap_content" android:progress="20" android:thumb="@drawable/seekbarimg" android:layout_weight="1"/>
Adapter
public class MusicAdapter extends BaseAdapter { private LayoutInflater minflate; //传递所有文件路径 private File[] musicDirs; public MusicAdapter(LayoutInflater minflate, File[] musicDirs) { super(); this.minflate = minflate; this.musicDirs = musicDirs; } @Override public int getCount() { // TODO Auto-generated method stub return musicDirs.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder vh = null; if (convertView == null) { vh = new ViewHolder(); convertView = minflate.inflate(R.layout.item_music_name, null); vh.mtextview = (TextView) convertView .findViewById(R.id.textview_music_name); vh.mtextview_author = (TextView) convertView .findViewById(R.id.textview_author_name); vh.img = (ImageView) convertView.findViewById(R.id.img); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } vh.mtextview.setText(musicDirs[position].getName()); //通过MediaMetadataRetriever的对象来获取音频文件的 //歌名、歌手、自带的图片 MediaMetadataRetriever mnr = new MediaMetadataRetriever(); Log.d("路径", musicDirs[position].getAbsolutePath()); mnr.setDataSource(musicDirs[position].getAbsolutePath()); String author = mnr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); //获取作者名,不为空对textview进行重新设置 if (author != null) { vh.mtextview_author.setText(author); } else { vh.mtextview_author.setText("<未知>"); } //获取二进制图片 byte[] img = mnr.getEmbeddedPicture(); if (img != null) { //将二进制文件转换成位图进行添加专辑图片 Bitmap bitmap = BitmapFactory.decodeByteArray(img, 0, img.length); vh.img.setImageBitmap(bitmap); } else { vh.img.setImageResource(R.drawable.audio_identify_singer_default); } return convertView; } class ViewHolder { TextView mtextview; TextView mtextview_author; ImageView img; }}
这里我们将重点学习的地方提取出来。
获取作者与图片
//通过MediaMetadataRetriever的对象来获取音频文件的 //歌名、歌手、自带的图片 MediaMetadataRetriever mnr = new MediaMetadataRetriever(); Log.d("路径", musicDirs[position].getAbsolutePath()); mnr.setDataSource(musicDirs[position].getAbsolutePath()); String author = mnr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
//获取二进制图片 byte[] img = mnr.getEmbeddedPicture(); if (img != null) { //将二进制文件转换成位图进行添加专辑图片 Bitmap bitmap = BitmapFactory.decodeByteArray(img, 0, img.length); vh.img.setImageBitmap(bitmap); } else { vh.img.setImageResource(R.drawable.audio_identify_singer_default); }
②获取并传递音频文件路径,开启Service
musicDir = Environment.getExternalStorageDirectory(); musicDir = new File(musicDir, "/musics"); files = musicDir.listFiles();
Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putStringArrayListExtra("all_music_path", files_path); startService(intent);
监听ListView
在这里每次点击后开启服务,设置开始键样式为
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //设置为选中状态,样式改变 mradoibutton_start.setChecked(true); Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putExtra("type", Config.START_NEW_MUSIC_LISTVIEW); intent.putExtra("music_position",position ); intent.putExtra("all_music_path", files_path); startService(intent); }
③Service中创建线程,开启音乐
在onStartCommand方法中调用而不是onCreate方法 ,因为在每次服务启动的时候该方法都会调用,而onCreate方法则是只有在服务被创建的时候才被调用。
public void startNewMusiclistview(){ if(mediaplayer==null){ mediaplayer=new MediaPlayer(); } mediaplayer.reset(); try { mediaplayer.setDataSource(musicspath.get(musicposition).toString()); mediaplayer.prepare(); mediaplayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaplayer.start(); mediaplayer.getCurrentPosition(); int duration=mediaplayer.getDuration(); Intent intent2=new Intent("play"); intent2.putExtra("type", 0); intent2.putExtra("totaltime",mediaplayer.getDuration()); intent2.putExtra("ischecked", true); //这里发送广播给MainActivity,将总时间传递给SeekBar sendBroadcast(intent2); //开启线程,发送广播给MainActivity //用于与seekbar关联,设置SeekBar进度 MyThreadPlay myplaythread=new MyThreadPlay(); myplaythread.start(); } }); //为了循环播放音乐,对当前音频的播放完成情况进行检测 //使它能够在播放完一首歌曲之后播放下一首歌曲 mediaplayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { //最后一个文件时,让位置重新回到开始,通过递归进行循环播放 if(musicposition==musicspath.size()-1){ musicposition=0; }else{ musicposition++; } startNewMusiclistview(); } }); } 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(); } }
Ⅱ创建线程,发送广播与SeekBar可拖动滚动条关联
①由音频文件属性设置Seekbar进度
MusicService中发送广播
class MyThreadPlay extends Thread{ @Override public void run() { while(mediaplayer.isPlaying()){ Intent intent=new Intent("play"); intent.putExtra("type", 1); intent.putExtra("currentime", mediaplayer.getCurrentPosition()); sendBroadcast(intent); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
MainActivity接收
注意接收者在mainActivity中的动态注册与注销
动态注册BroadcastReceiver
receiver = new MyReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("play"); registerReceiver(receiver, filter);
BroadcastReceiver的继承类
//该类用于接收MusicService发过来的广播,用于设置textview与seekbarclass MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int type = intent.getIntExtra("type", 0); //由于我们获得的时间是毫秒数,因此要进行相应转换 Date date = new Date(); SimpleDateFormat format=new SimpleDateFormat("mm:ss"); //通过判断intent的type来确定设置进度还是设置时间 switch (type) { case 0: int duration = intent.getIntExtra("totaltime", 0); date.setTime(duration); String format_duration= format.format(date); //设置seekbar最大值,这样才能控制进度 mseekbar.setMax(duration); mtv_totaltime.setText("" + format_duration); break; case 1: currenttime = intent.getIntExtra("currentime", 0); date.setTime(currenttime); String format_currenttime= format.format(date); mtv_currenttime.setText(format_currenttime); mseekbar.setProgress(currenttime); break; default: break; } } }
注销BroadcastReceiver
@Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); }
②通过监听SeekBar的进度改变音频文件进度
上面的代码中我们只实现了音频文件对SeekBar进度的改变时不行的,下面我们通过对SeekBar的监听来改变音频文件
mseekbar.setOnSeekBarChangeListener(this);
//SeekBar改变过程中时调用 @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } //SeekBar开始改变时调用 @Override public void onStartTrackingTouch(SeekBar seekBar) { } //SeekBar最终停止改变时调用,我们在这个方法中进行对音频文件的进度修改 @Override public void onStopTrackingTouch(SeekBar seekBar) { Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putExtra("type", Config.SEEKTO); intent.putExtra("progress", mseekbar.getProgress()); startService(intent); }
MusicService中进行修改进度
int progress=intent.getIntExtra("progress", 0); mediaplayer.seekTo(progress);
Ⅲ上一曲、下一曲、开始、停止按钮的监听
MainActivity
上一曲、下一曲的监听只是传递的类型不同,只有停止开始按钮不太一样,因为它在开始与停止状态的图片有变化。
@Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), MusicService.class); switch (v.getId()) { case R.id.bt_previeous: intent.putExtra("type", Config.SELECT_PREVIOUS_BY_TOGGLEBUTTON); startService(intent); break; case R.id.bt_next: intent.putExtra("type", Config.SELECT_NEXT_BY_TOGGLEBUTTON); startService(intent); break; case R.id.bt_start: if(flag){ intent.putExtra("type", Config.START_NOW_BY_TOGGLEBUTTON); intent.putExtra("mcurrenttime",currenttime); startService(intent); flag=!flag; }else{ intent.putExtra("type", Config.PAUSE_NOW_BY_TOGGLEBUTTON); startService(intent); flag=!flag; } break; default: break; }
MusicService中的只是把当前文件位置进行加、减、暂停、继续
int type=intent.getIntExtra("type",222); switch (type) { case Config.START_NEW_MUSIC_LISTVIEW: musicposition=intent.getIntExtra("music_position", 0); currentposition=musicposition; startNewMusiclistview(); break; case Config.SEEKTO: int progress=intent.getIntExtra("progress", 0); mediaplayer.seekTo(progress); break; case Config.START_NOW_BY_TOGGLEBUTTON: int currenttime=intent.getIntExtra("mcurrenttime", 0); while (!mediaplayer.isPlaying()) { mediaplayer.start(); } // startNewMusiclistview(); break; case Config.PAUSE_NOW_BY_TOGGLEBUTTON: while (mediaplayer.isPlaying()) { mediaplayer.pause(); } break; case Config.SELECT_PREVIOUS_BY_TOGGLEBUTTON: Log.d("musicString",currentposition +""); if(currentposition==0){ musicposition=musicspath.size()-1; }else{ musicposition--; } currentposition=musicposition; startNewMusiclistview(); break; case Config.SELECT_NEXT_BY_TOGGLEBUTTON: if(currentposition==musicspath.size()-1){ musicposition=0; }else{ musicposition++; } currentposition=musicposition; startNewMusiclistview(); break; case 222:break; default: break; }
ⅣConfig.class文件
该文件中专门用于存放判别type的常量
package com.example.mymediaplayerdemo;public class Config { public static final int START_NEW_MUSIC_LISTVIEW=0x01; public static final int SEEKTO=0x02; public static final int START_NOW_BY_TOGGLEBUTTON=0x03; public static final int PAUSE_NOW_BY_TOGGLEBUTTON=0x04; public static final int SELECT_PREVIOUS_BY_TOGGLEBUTTON=0x05; public static final int SELECT_NEXT_BY_TOGGLEBUTTON=0x06;}
主要代码
MainActivity
public class MainActivity extends Activity implements OnClickListener, OnSeekBarChangeListener, OnItemClickListener { private ListView mlistview; private TextView mtv_currenttime; private TextView mtv_totaltime; private ToggleButton mradoibutton_pre; private ToggleButton mradoibutton_start; private ToggleButton mradoibutton_next; private SeekBar mseekbar; private File musicDir; private File[] files; private int seekbarprogress; private MusicAdapter madapter; private LayoutInflater inflater; private MyReceiver receiver; private ArrayList<String> files_path=new ArrayList<String>(); private int currenttime; private boolean flag=false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); mradoibutton_pre = (ToggleButton) findViewById(R.id.bt_previeous); mradoibutton_start = (ToggleButton) findViewById(R.id.bt_start); mradoibutton_next = (ToggleButton) findViewById(R.id.bt_next); mseekbar = (SeekBar) findViewById(R.id.seekbar); mlistview = (ListView) findViewById(R.id.listview); mtv_totaltime = (TextView) findViewById(R.id.textview_totaltime); mtv_currenttime = (TextView) findViewById(R.id.textview_currenttime); receiver = new MyReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("play"); registerReceiver(receiver, filter); musicDir = Environment.getExternalStorageDirectory(); musicDir = new File(musicDir, "/musics"); files = musicDir.listFiles();// for (File file : files) {// Log.d("音乐文件", file.getName() + "路径" + file.getAbsolutePath());// // } for (int i = 0; i < files.length; i++) { files_path.add(files[i].getAbsolutePath().toString()); Log.d("files_path", files_path.get(i)); } Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putStringArrayListExtra("all_music_path", files_path); startService(intent); inflater = getLayoutInflater(); madapter = new MusicAdapter(inflater, files); mlistview.setAdapter(madapter); mlistview.setOnItemClickListener(this); mradoibutton_pre.setOnClickListener(this); mradoibutton_start.setOnClickListener(this); mradoibutton_next.setOnClickListener(this); mseekbar.setOnSeekBarChangeListener(this); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mradoibutton_start.setChecked(true); Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putExtra("type", Config.START_NEW_MUSIC_LISTVIEW); intent.putExtra("music_position",position ); intent.putExtra("all_music_path", files_path); startService(intent); } class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int type = intent.getIntExtra("type", 0); Date date = new Date(); SimpleDateFormat format=new SimpleDateFormat("mm:ss"); switch (type) { case 0: int duration = intent.getIntExtra("totaltime", 0); date.setTime(duration); String format_duration= format.format(date); mseekbar.setMax(duration); mtv_totaltime.setText("" + format_duration); break; case 1: currenttime = intent.getIntExtra("currentime", 0); date.setTime(currenttime); String format_currenttime= format.format(date); mtv_currenttime.setText(format_currenttime); mseekbar.setProgress(currenttime); break; default: break; } } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(receiver); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub } @Override public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } @Override public void onStopTrackingTouch(SeekBar seekBar) { Intent intent = new Intent(getApplicationContext(), MusicService.class); intent.putExtra("type", Config.SEEKTO); intent.putExtra("progress", mseekbar.getProgress()); startService(intent); } @Override public void onClick(View v) { Intent intent = new Intent(getApplicationContext(), MusicService.class); switch (v.getId()) { case R.id.bt_previeous: intent.putExtra("type", Config.SELECT_PREVIOUS_BY_TOGGLEBUTTON); startService(intent); break; case R.id.bt_next: intent.putExtra("type", Config.SELECT_NEXT_BY_TOGGLEBUTTON); startService(intent); break; case R.id.bt_start: if(flag){ intent.putExtra("type", Config.START_NOW_BY_TOGGLEBUTTON); intent.putExtra("mcurrenttime",currenttime); startService(intent); flag=!flag; }else{ intent.putExtra("type", Config.PAUSE_NOW_BY_TOGGLEBUTTON); startService(intent); flag=!flag; } break; default: break; } }}
MusicService
public class MusicService extends Service{ private MediaPlayer mediaplayer; private int musicposition; private ArrayList<String> musicspath; private int currentposition; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if(musicspath==null){ musicspath=intent.getStringArrayListExtra("all_music_path"); } int type=intent.getIntExtra("type",222); switch (type) { case Config.START_NEW_MUSIC_LISTVIEW: musicposition=intent.getIntExtra("music_position", 0); currentposition=musicposition; startNewMusiclistview(); break; case Config.SEEKTO: int progress=intent.getIntExtra("progress", 0); mediaplayer.seekTo(progress); break; case Config.START_NOW_BY_TOGGLEBUTTON: int currenttime=intent.getIntExtra("mcurrenttime", 0); while (!mediaplayer.isPlaying()) { mediaplayer.start(); } // startNewMusiclistview(); break; case Config.PAUSE_NOW_BY_TOGGLEBUTTON: while (mediaplayer.isPlaying()) { mediaplayer.pause(); } break; case Config.SELECT_PREVIOUS_BY_TOGGLEBUTTON: Log.d("musicString",currentposition +""); if(currentposition==0){ musicposition=musicspath.size()-1; }else{ musicposition--; } currentposition=musicposition; startNewMusiclistview(); break; case Config.SELECT_NEXT_BY_TOGGLEBUTTON: if(currentposition==musicspath.size()-1){ musicposition=0; }else{ musicposition++; } currentposition=musicposition; startNewMusiclistview(); break; case 222:break; default: break; } return super.onStartCommand(intent, flags, startId); } public void startNewMusiclistview(){ if(mediaplayer==null){ mediaplayer=new MediaPlayer(); } mediaplayer.reset(); try { mediaplayer.setDataSource(musicspath.get(musicposition).toString()); mediaplayer.prepare(); mediaplayer.setOnPreparedListener(new OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mediaplayer.start(); mediaplayer.getCurrentPosition(); int duration=mediaplayer.getDuration(); Intent intent2=new Intent("play"); intent2.putExtra("type", 0); intent2.putExtra("totaltime",mediaplayer.getDuration()); intent2.putExtra("ischecked", true); sendBroadcast(intent2); MyThreadPlay myplaythread=new MyThreadPlay(); myplaythread.start(); } }); mediaplayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { if(musicposition==musicspath.size()-1){ musicposition=0; }else{ musicposition++; } startNewMusiclistview(); } }); } 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(); } } class MyThreadPlay extends Thread{ @Override public void run() { while(mediaplayer.isPlaying()){ Intent intent=new Intent("play"); intent.putExtra("type", 1); intent.putExtra("currentime", mediaplayer.getCurrentPosition()); sendBroadcast(intent); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }}
Adapter
public class MusicAdapter extends BaseAdapter { private LayoutInflater minflate; private File[] musicDirs; public MusicAdapter(LayoutInflater minflate, File[] musicDirs) { super(); this.minflate = minflate; this.musicDirs = musicDirs; } @Override public int getCount() { // TODO Auto-generated method stub return musicDirs.length; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return position; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder vh = null; if (convertView == null) { vh = new ViewHolder(); convertView = minflate.inflate(R.layout.item_music_name, null); vh.mtextview = (TextView) convertView .findViewById(R.id.textview_music_name); vh.mtextview_author = (TextView) convertView .findViewById(R.id.textview_author_name); vh.img = (ImageView) convertView.findViewById(R.id.img); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } vh.mtextview.setText(musicDirs[position].getName()); MediaMetadataRetriever mnr = new MediaMetadataRetriever(); Log.d("路径", musicDirs[position].getAbsolutePath()); mnr.setDataSource(musicDirs[position].getAbsolutePath()); String author = mnr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); if (author != null) { vh.mtextview_author.setText(author); } else { vh.mtextview_author.setText("<未知>"); } byte[] img = mnr.getEmbeddedPicture(); if (img != null) { Bitmap bitmap = BitmapFactory.decodeByteArray(img, 0, img.length); vh.img.setImageBitmap(bitmap); } else { vh.img.setImageResource(R.drawable.audio_identify_singer_default); } return convertView; } class ViewHolder { TextView mtextview; TextView mtextview_author; ImageView img; }}
- Android 酷炫来袭:制作属于你自己的音频播放器(综合运用MediaPlayer、Service、Broadcast、ListView、SeekBar)
- android MediaPlayer 音频播放器
- Android 音乐播放器的开发教程(七)运用Broadcast实现service与activity的通信 ----- 小达
- Android MediaPlayer播放音频
- android 音频播放--MediaPlayer
- Android:MediaPlayer播放音频
- android MediaPlayer音频播放
- android MediaPlayer 播放各种来源的音频
- Android 音频的播放之二MediaPlayer
- android 音频播放器 MediaPlayer
- android mediaPlayer音频播放器基本用法
- Android学习之MediaPlayer 音频播放器
- Android音频播放(SoundPool与 MediaPlayer)
- Android MediaPlayer+SeekBar播放音频出现卡顿边长可能问题
- [Android]结合MediaPlayer和Service的音乐播放器
- [Android]结合MediaPlayer和Service的音乐播放器
- Android两种播放视频的方法(SurfaceView+MediaPlayer+SeekBar)跟(VideoView+MediaController)
- android MediaPlayer音频播放demo
- java之代理
- poj 2186 Popular Cows 有向图强连通分量 tarjan
- 数组和面向对象(封装)
- ubuntu14.04更新源出错解决
- Android学习——其他View
- Android 酷炫来袭:制作属于你自己的音频播放器(综合运用MediaPlayer、Service、Broadcast、ListView、SeekBar)
- c++中字符数组与字符串的转换
- 数据结构之双向循环链表操作4-(插入,删除,建立等)
- Teapot
- c++11
- 金融分析之股票相关历史数据爬虫地址
- atoi()函数的实现
- 二叉树的经典技巧及算法 I
- Docker安装使用以及通过docker配置 galaxy 分析高通量数据