首页 > 系统 > Android > 正文

Android之MediaPlayer(两种)基本使用方式

2019-11-09 13:49:09
字体:
来源:转载
供稿:网友

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表