文章出處

首先你你需要知道MediaPlayer這個類的一些方法:

  • int getDuration():獲取流媒體的總播放時長,單位是毫秒。
  • int getCurrentPosition():獲取當前流媒體的播放的位置,單位是毫秒。
  • void seekTo(int msec):設置當前MediaPlayer的播放位置,單位是毫秒。
  • void setLooping(boolean looping):設置是否循環播放。
  • boolean isLooping():判斷是否循環播放。
  • boolean isPlaying():判斷是否正在播放。
  • void prepare():同步的方式裝載流媒體文件。
  • void prepareAsync():異步的方式裝載流媒體文件。
  • void release ():回收流媒體資源。
  • void setAudioStreamType(int streamtype):設置播放流媒體類型。
  • void setWakeMode(Context context, int mode):設置CPU喚醒的狀態。
  • setNextMediaPlayer(MediaPlayer next):設置當前流媒體播放完畢,下一個播放的MediaPlayer。

注意一下兩點

  1. 在使用MediaPlayer播放一段流媒體的時候,需要使用prepare()或prepareAsync()方法把流媒體裝載進MediaPlayer,才可以調用start()方法播放流媒體。                 
  2. setAudioStreamType()方法用于指定播放流媒體的類型,它傳遞的是一個int類型的數據,均以常量定義在AudioManager類中, 一般我們播放音頻文件,設置為AudioManager.STREAM_MUSIC即可。

在播放下一首歌曲的時候需要釋放MediaPlayer的資源:

if (mediaPlayer != null && mediaPlayer.isPlaying()) {
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
    }

然后就是關于BinderService:

  • 先看一下按下Back鍵之后Activity的生命周期:onPause()-->onStop()-->onDestory()-->onCreate()-->onStart()-->onResum();

  • BinderService的存活于綁定的Activity有關,當與之綁定的Activity被銷毀的時候,Service也會銷毀,根據生命周期,我們就可以知道,當你按下Back鍵的時候,Service也會銷毀,這樣音樂就會停止播放,但是我們使用的大多數音樂播放器軟件都按下Back鍵之后依舊在播放,所以,就有了我們的startServuce()和binderService()混合開發,因為startService()的生命周期與activity無關。

  • 我們的主要邏輯是,用startService播放音樂,用binderService()控制音樂的播放。

  • startService很常見,就不說了,你需要知道binderService的使用,其實binderService就是用一個繼承與BInder的MyBinder的類,作為一個中間對象,在Activity中對Service中的方法進行調用,從而實現控制。

下面我們開始編寫我們的音樂播放器

創建一個MusicItem類記錄一些音樂的信息

public class MusicItem {
    public String name;
    public String data;
    public String artist;
    public long time;
}

請求讀寫權限并且獲取手機上的所有音頻文件

private void initData(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (PackageManager.PERMISSION_DENIED == checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)){
                requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},0);
            }
        }

        itemList = new ArrayList<>();

        new Thread(){
            @Override
            public void run() {
                super.run();
                ContentResolver resolver = mContext.getContentResolver();
                Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                String[] objs ={
                        MediaStore.Audio.Media.DISPLAY_NAME,
                        MediaStore.Audio.Media.DATA,
                        MediaStore.Audio.Media.ARTIST,
                        MediaStore.Audio.Media.DURATION,
                };

                Cursor cursor = resolver.query(uri,objs,null,null,null);
                if (cursor !=null){
                    while (cursor.moveToNext()){
                        MusicItem musicItem = new MusicItem();
                        itemList.add(musicItem);

                        String name = cursor.getString(0);
                        musicItem.name = name;
                        String data = cursor.getString(1);
                        musicItem.data = data;
                        String aritst = cursor.getString(2);
                        musicItem.artist = aritst;
                        long time = cursor.getLong(3);
                        musicItem.time = time;
                    }
                  cursor.close();
                }
                handler.sendEmptyMessage(0);
            }
        }.start();

    }

獲取到手機上的所有的音頻文件之后,發送一個handler消息,將musicItem的集合itemList中的數據顯示在Adapter上(Adapter的代碼這里不拿出來說了,很見到的)

創建一個MusicService類,繼承與Service

這個類用來后臺播放音樂

public class MusicService extends Service {

    private MediaPlayer player;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    public void onPause(){
        player.pause();
    }
    
    public void onStart(){
        player.start();
    }
    
    public void openAudio(String uri) throws IOException {
        if (player != null && player.isPlaying()){
            player.stop();
            player.release();
            player = null;
        }
        player = new MediaPlayer();
        player.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            player.setDataSource(uri);
            player.prepare();
            player.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public class MyBinder extends Binder{
        MusicService getService(){
            return MusicService.this;
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        player.stop();
        player.reset();
        player.release();
    }
}
  • MyBinder是Activity與MusicService進行通信的中間對象(這里只實現了播放和暫停的功能)

綁定MusicSerivce

下面是Activity的onCreate()方法:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        mContext = this;

        lvList = (ListView) findViewById(R.id.lv_list);
        Button start = (Button) findViewById(R.id.start);
        Button pasue = (Button) findViewById(R.id.pause);
        pasue.setOnClickListener(this);
        start.setOnClickListener(this);
        Intent intent = new Intent(MainActivity.this,MusicService.class);
        startService(intent);
        bindService(intent,conn,BIND_AUTO_CREATE);
        initData();
    }

綁定Service:

private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            service1 = ((MusicService.MyBinder) service).getService();
        }

        @Override

        public void onServiceDisconnected(ComponentName name) {

        }
    };

點擊ListView中的Item的時候播放音樂

實現暫停和播放:

private android.os.Handler handler = new android.os.Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (itemList != null && itemList.size()>0){
                MusicAdapter adapter = new MusicAdapter(mContext,itemList);
                lvList.setAdapter(adapter);
                lvList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                        try {
                            service1.openAudio(itemList.get(position).data);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    };
@Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start:
                service1.onStart();
                break;

            case R.id.pause:
                service1.onPause();
                break;

        }
    }
  • 當綁定成功的時候,返回的是一個MusicService對象,拿著這個Service對象就能對MusicService中的方法進行調用了。
  • 首先startService,然后在binderService讓Activity與Service之間進行通信,然Activity通過MyBinder對象對Service中的方法進行調用。

Service的銷毀

在Activity中的onDestory()方法中對MusicService進行取消綁定:

@Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
    }

記得添加讀寫權限


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()