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=new MediaPlayer();           //设置类型           mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);           /* 得到文件路径 *//* 注:文件存放在SD卡的根目录,一定要进行prepare()方法,使硬件进行准备 */           File file = new File(Environment.getExternalStorageDirectory(),"a.mp3");           try{               /* 为MediaPlayer 设置数据源 */               mediaPlayer.setDataSource(file.getAbsolutePath());                /* 准备 */               mediaPlayer.prepare();           }catch(Exception ex){               ex.printStackTrace();           }           mediaPlayer.start();           // 把图标变为暂停图标           imageButton.setImageResource(android.R.drawable.ic_media_pause);           //获取音乐的总时长           int duration=mediaPlayer.getDuration();           //设置进度条的最大值为音乐总时长           seekBar.setMax(duration);           new MyThread().start();//           //实例化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"?>        

程序说明:

以上例子介绍了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并赋予权限,允许读取外部存储空间。

        

以上步骤是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:

                                                                  

这样就可以实现简单音乐播放器的播放。

效果图

      

总结

  1. 读取SD卡内存的时候,应该使用android.os.Environment库中的getExternalStorageDirectory()方法,然而并不能生效。应该再使用getAbsolutePath()获取绝对路径后读取音乐才生效。
  2. 切换歌曲的时候try块不能正确执行。检查过后,也是执行了stop()函数后再重新setDataSource()来切换歌曲的,但是没有效果。查阅资料后,发现setDataSource()之前需要调用reSet()方法,才可以重新设置歌曲。

简述如何使用Handler实时更新UI

方法一:
Handle的post方法,在post的Runable的run方法中,使用postDelay方法再次post该Runable对象,在Runable中更新UI,达到实时更新UI的目的
方法二:
多开一个线程,线程写一个持续循环,每次进入循环内即post一次Runable,然后休眠1000ms,亦可做到实时更新UI











更多相关文章

  1. android EditText 不自动弹出键盘的方法
  2. Android(安卓)AsyncTask Download
  3. Android(安卓)中的看门狗—Watchdog
  4. Android禁用返回键
  5. android Fragment + FragmentStatePagerAdapter的恢复问题解决
  6. android 自动更新apk版本
  7. Android(安卓)MediaPlayer 常用方法介绍
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. windows系、公司内网环境 如何下载androi
  2. android RXJava2.0(一)
  3. Android快速开发框架Android_BaseLib,集成
  4. Activity被系统重启
  5. Android属性动画Property Animation系列
  6. Android模拟器无法保存数据
  7. Android 使用ActivityOptions实现Activit
  8. 【Android】android:padding属性设置对Im
  9. Android Studio生成javadoc出错的解决办
  10. 关于android中的EditView,TextView的图片