1.播放应用的资源文件(res/raw/)
java代码示例:
MainActivity.java
public class MainActivity extends AppCompatActivity { PRivate MediaPlayer mediaPlayer; private SeekBar seekBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBar = (SeekBar) findViewById(R.id.seekBar); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {} @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) { //获取拖动结束之后的位置 int progress=seekBar.getProgress(); //跳转到某个位置播放 mediaPlayer.seekTo(progress); } }); } public void play(View view){ ImageButton imageButton= (ImageButton) view; if(mediaPlayer==null){ //实例化MediaPlayer mediaPlayer = MediaPlayer.create(this, R.raw.one); mediaPlayer.start(); //把图标变为暂停图标 imageButton.setImageResource(android.R.drawable.ic_media_pause); //获取音乐的总时长 int duration=mediaPlayer.getDuration(); //设置进度条的最大值为音乐总时长 seekBar.setMax(duration); new MyThread().start(); }else if(mediaPlayer.isPlaying()){ mediaPlayer.pause(); //把图标变为播放图标 imageButton.setImageResource(android.R.drawable.ic_media_play); }else{ mediaPlayer.start(); //把图标变为暂停图标 imageButton.setImageResource(android.R.drawable.ic_media_pause); } } class MyThread extends Thread{ @Override public void run() { super.run(); while(seekBar.getProgress()<=seekBar.getMax()){ //获取当前位置音乐播放的位置 int currentPosition=mediaPlayer.getCurrentPosition(); //让进度条滚动起来 seekBar.setProgress(currentPosition); } } }}简单的一个布局文件:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="16dp" android:layout_marginLeft="16dp" > <SeekBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:id="@+id/seekBar" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_media_play" android:onClick="play" /></LinearLayout>程序说明:
以上例子描述了MediaPlayer播放应用内的音频步骤和方式.下面介绍的是播放内存卡中的音频
2.播放外部存储上的音频资源文件(sdcard)
代码实现
1)导入歌曲到手机SD卡的QQmusic/song目录中,这里我随便导入了几首歌曲:《三生三世》、《爱丫爱丫》、《安和桥》和《和你在一起》,路径可随自己而定。
新建一个类MusicService继承Service,在类中定义一个MyBinder,有一个方法用于返回MusicService本身,在重载onBind()方法的时候返回
public final IBinder binder = new MyBinder(); public class MyBinder extends Binder{ MusicService getService() { return MusicService.this; } } /** * onBind 是 Service 的虚方法,因此我们不得不实现它。 * 返回 null,表示客服端不能建立到此服务的连接。 */ @Override public IBinder onBind(Intent intent) { return binder; }2)在MusicService中,声明一个MediaPlayer变量,进行设置歌曲路径,这里我选择歌曲1作为初始化时候的歌曲private String[] musicDir = new String[]{ Environment.getExternalStorageDirectory().getAbsolutePath()+"/qqmusic/song/三生三世.mp3", Environment.getExternalStorageDirectory().getAbsolutePath()+"/qqmusic/song/爱丫爱丫.mp3", Environment.getExternalStorageDirectory().getAbsolutePath()+"/qqmusic/song/安和桥.mp3", Environment.getExternalStorageDirectory().getAbsolutePath() +"/qqmusic/song/和你在一起.mp3"}; private int musicIndex = 1; public static MediaPlayer mp = new MediaPlayer(); public MusicService() { try { musicIndex = 1; mp.setDataSource(musicDir[musicIndex]); mp.prepare(); } catch (Exception e) { e.printStackTrace(); } }3)功能:有相关歌曲播放、暂停、停止、退出的方法,还可以切换上一首和下一首,主要方法如下://播放/暂停按钮 public void playOrPause() { if(mp.isPlaying()){ mp.pause(); } else { mp.start(); } } //下一首 public void nextMusic() { if(mp != null && musicIndex < 3) { mp.stop(); try { mp.reset(); mp.setDataSource(musicDir[musicIndex+1]); musicIndex++; mp.prepare(); mp.seekTo(0); mp.start(); } catch (Exception e) { Log.d("hint", "can't jump next music"); e.printStackTrace(); } }else { Toast.makeText(this, "没有更多歌曲啦", Toast.LENGTH_SHORT).show(); } } //上一首 public void preMusic() { if(mp != null && musicIndex > 0) { mp.stop(); try { mp.reset(); mp.setDataSource(musicDir[musicIndex-1]); musicIndex--; mp.prepare(); mp.seekTo(0); mp.start(); } catch (Exception e) { Log.d("hint", "can't jump pre music"); e.printStackTrace(); } }else{ Toast.makeText(this, "已经是第一首啦", Toast.LENGTH_SHORT).show(); } }4)注册MusicService并赋予权限,允许读取外部存储空间。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <service android:name="com.pxd.mediaplayer.MusicService" android:exported="true"/>以上步骤是MusicService类核心代码。
接下来我们需在
5)MainAcitvity中声明ServiceConnection,调用bindService保持与MusicService通信,通过intent的事件进行通信,在onCreate()函数中绑定Service
private ServiceConnection sc = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { musicService = ((MusicService.MyBinder)iBinder).getService(); } @Override public void onServiceDisconnected(ComponentName componentName) { musicService = null; } }; private void bindServiceConnection() { Intent intent = new Intent(Main.this, MusicService.class); startService(intent); bindService(intent, sc, this.BIND_AUTO_CREATE); }@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); musicService = new MusicService(); bindServiceConnection(); seekBar = (SeekBar)this.findViewById(R.id.MusicSeekBar); seekBar.setProgress(musicService.mp.getCurrentPosition()); seekBar.setMax(musicService.mp.getDuration()); musicBegin = (TextView)this.findViewById(R.id.MusicBegin); musicTime = (TextView)this.findViewById(R.id.MusicTime); musicStatus=(TextView)this.findViewById(R.id.MusicStatus); btnPlayOrPause = (ImageButton) findViewById(R.id.BtnPlayorPause); Log.d("hint", Environment.getExternalStorageDirectory().getAbsolutePath()+"/You.mp3"); }bindService函数回调onSerciceConnented函数,通过MusiceService函数下的onBind()方法获得binder对象并实现绑定
6)通过Handle实时更新UI,这里主要使用了post方法并在Runnable中调用postDelay方法实现实时更新UI,Handle.post方法在onResume()中调用,使得程序刚开始时和重新进入应用时能够更新UI
在Runnable中更新SeekBar的状态,并设置SeekBar滑动条的响应函数,使歌曲跳转到指定位置
public android.os.Handler handler = new android.os.Handler(); public Runnable runnable = new Runnable() { @Override public void run() { if(musicService.mp.isPlaying()) { musicStatus.setText("状态:正在播放....."); btnPlayOrPause.setImageResource(android.R.drawable.ic_media_pause); } else { musicStatus.setText("状态:未播放"); btnPlayOrPause.setImageResource(android.R.drawable.ic_media_play); } musicBegin.setText(time.format(musicService.mp.getCurrentPosition())); musicTime.setText(time.format(musicService.mp.getDuration())); seekBar.setProgress(musicService.mp.getCurrentPosition()); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { musicService.mp.seekTo(seekBar.getProgress()); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); handler.postDelayed(runnable, 100); } }; @Override protected void onResume() { if(musicService.mp.isPlaying()) { musicStatus.setText("状态:正在播放....."); btnPlayOrPause.setImageResource(android.R.drawable.ic_media_pause); } else { musicStatus.setText("状态:未播放"); btnPlayOrPause.setImageResource(android.R.drawable.ic_media_play); } seekBar.setProgress(musicService.mp.getCurrentPosition()); seekBar.setMax(musicService.mp.getDuration()); handler.post(runnable); super.onResume(); Log.d("hint", "handler post runnable"); }7)给每个按钮设置响应函数,在onDestroy()中添加解除绑定,避免内存泄漏
public void onClick(View view) { switch (view.getId()) { case R.id.BtnPlayorPause: musicService.playOrPause(); break; case R.id.BtnQuit: handler.removeCallbacks(runnable); unbindService(sc); try { System.exit(0); } catch (Exception e) { e.printStackTrace(); } break; case R.id.btnPre: musicService.preMusic(); // Toast.makeText(musicService, "上一首切换", Toast.LENGTH_SHORT).show(); break; case R.id.btnNext: musicService.nextMusic(); //Toast.makeText(musicService, "下一首切换", Toast.LENGTH_SHORT).show(); break; default: break; } } @Override public void onDestroy() { unbindService(sc); super.onDestroy(); }8)在Button中赋予onClick属性指向接口函数main.xml:
<LinearLayout 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:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".Main"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MusicStatus" android:layout_gravity="center_horizontal" android:textSize="20sp" android:text=""/> <SeekBar android:layout_marginTop="16dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/MusicSeekBar"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MusicBegin" android:text=" "/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/MusicTime" android:layout_marginLeft="270dp" android:text=" "/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal"> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnPre" android:src="@android:drawable/ic_media_previous" android:onClick="onClick" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/BtnPlayorPause" android:src="@android:drawable/ic_media_play" android:onClick="onClick" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnNext" android:src="@android:drawable/ic_media_next" android:onClick="onClick"/> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/BtnQuit" android:text="退出" android:onClick="onClick"/></LinearLayout>这样就可以实现简单音乐播放器的播放。效果图

总结
读取SD卡内存的时候,应该使用android.os.Environment库中的getExternalStorageDirectory()方法,然而并不能生效。应该再使用getAbsolutePath()获取绝对路径后读取音乐才生效。切换歌曲的时候try块不能正确执行。检查过后,也是执行了stop()函数后再重新setDataSource()来切换歌曲的,但是没有效果。查阅资料后,发现setDataSource()之前需要调用reSet()方法,才可以重新设置歌曲。简述如何使用Handler实时更新UI
方法一:Handle的post方法,在post的Runable的run方法中,使用postDelay方法再次post该Runable对象,在Runable中更新UI,达到实时更新UI的目的方法二:多开一个线程,线程写一个持续循环,每次进入循环内即post一次Runable,然后休眠1000ms,亦可做到实时更新UI
新闻热点
疑难解答