Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發本地及網絡Mp3音樂播放器(六)實現獨立音樂播放界面

Android開發本地及網絡Mp3音樂播放器(六)實現獨立音樂播放界面

編輯:關於Android編程

實現功能:
功能1:點擊MyMusicListFragment(本地音樂)底部UI中的專輯封面圖片打開的PlayActivity(獨立音樂播放界面)
PlayActivity中,顯示正在播放的歌名
PlayActivity中,顯示專輯封面圖片(大圖)
PlayActivity中,顯示上一首按鈕,實現對應功能
PlayActivity中,顯示暫停播放按鈕,實現對應功能
PlayActivity中,顯示下一首,實現對應功能
功能2:實現同步MyMusicListFragment(本地音樂界面)和PlayActivity(獨立音樂播放界面)信息同步
播放暫停按鈕狀態與圖片同步
歌曲位置同步(也就是第幾首歌曲等信息同步)

歡迎移動開發愛好者交流:我的微信是iwanghang

另外,我打算開始找工作,如果沈陽或周邊城市公司有意,也請與我聯系。

實現效果如圖:

\

\

\

\

 

實現代碼如下:
PlayActivity如下:
 

package com.iwanghang.drmplayer;

import android.graphics.Bitmap;
import android.os.Bundle;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;


import com.iwanghang.drmplayer.utils.MediaUtils;
import com.iwanghang.drmplayer.vo.Mp3Info;

import java.util.ArrayList;

/**
 *PlayActivity 點擊MyMusicListFragment(本地音樂)底部UI中的專輯封面圖片打開的Activity
 */
public class PlayActivity extends BaseActivity implements OnClickListener{
    private TextView textView1_title;//歌名
    private ImageView imageView1_ablum;//專輯封面圖片
    private SeekBar seekBar1;//進度條
    private TextView textView1_start_time,textView1_end_time;//開始時間,結束時間
    private ImageView imageView1_play_mode;//菜單
    private ImageView imageView3_previous,imageView2_play_pause,imageView1_next;//上一首,播放暫停,下一首

    private ArrayList mp3Infos;
    //private int position;//當前播放的位置
    private boolean isPause = false;//當前播放的是否為暫停狀態
    private static final int UPDATE_TIME = 0x1;//更新播放事件的標記

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music_play);
        //初始化界面信息
        textView1_title = (TextView) findViewById(R.id.textView1_title);//歌名
        imageView1_ablum = (ImageView) findViewById(R.id.imageView1_ablum);//專輯封面圖片
        seekBar1 = (SeekBar) findViewById(R.id.seekBar1);//進度條
        textView1_start_time = (TextView) findViewById(R.id.textView1_start_time);//開始時間
        textView1_end_time = (TextView) findViewById(R.id.textView1_end_time);//結束時間
        imageView1_play_mode = (ImageView) findViewById(R.id.imageView1_play_mode);//菜單
        imageView3_previous = (ImageView) findViewById(R.id.imageView3_previous);//上一首
        imageView2_play_pause = (ImageView) findViewById(R.id.imageView2_play_pause);//播放暫停
        imageView1_next = (ImageView) findViewById(R.id.imageView1_next);//下一首
        //注冊按鈕點擊監聽事件
        imageView1_play_mode.setOnClickListener(this);
        imageView2_play_pause.setOnClickListener(this);
        imageView3_previous.setOnClickListener(this);
        imageView1_next.setOnClickListener(this);


        mp3Infos = MediaUtils.getMp3Infos(this);
        //bindPlayService();//綁定服務,異步過程,綁定後需要取得相應的值,來更新界面
        myHandler = new MyHandler(this);

        //以下直接調用change()是不行的,因為異步問題,會發生NullPointerException空指針異常
        //從MyMusicListFragment的專輯封面圖片點擊時間傳過來的position(當前播放的位置)
        //position = getIntent().getIntExtra("position",0);
        //change(position);

        //通過在BaseActivity中綁定Service,添加如下代碼實現change()
        //musicUpdatrListener.onChange(playService.getCurrentProgeress());

        //從MyMusicListFragment的專輯封面圖片點擊時間傳過來的isPause(當前播放的是否為暫停狀態)
        //isPause = getIntent().getBooleanExtra("isPause",false);
    }

    //把播放服務的綁定和解綁放在onResume,onPause裡,好處是,每次回到當前Activity就獲取一次播放狀態
    @Override
    protected void onResume() {
        super.onResume();
        bindPlayService();
    }

    @Override
    protected void onPause() {
        super.onPause();
        unbindPlayService();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindPlayService();//解綁服務
    }

    //Handler用於更新已經播放時間
    private static MyHandler myHandler;
    static class MyHandler extends Handler{
        private PlayActivity playActivity;
        public MyHandler(PlayActivity playActivity){
            this.playActivity = playActivity;
        }
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (playActivity!=null){
                switch (msg.what){
                    case UPDATE_TIME://更新時間(已經播放時間)
                        playActivity.textView1_start_time.setText(MediaUtils.formatTime(msg.arg1));
                        break;
                }
            }
        }
    }

    @Override
    public void publish(int progress) {
        //以下是是直接調用線程,但是不能這樣做,會報錯,線程異常
        //textView1_start_time.setText(MediaUtils.formatTime(progress));
        //所以,我們需要使用Handler
        Message msg = myHandler.obtainMessage(UPDATE_TIME);//用於更新已經播放時間
        msg.arg1 = progress;//用於更新已經播放時間
        myHandler.sendMessage(msg);//用於更新已經播放時間

        seekBar1.setProgress(progress);
    }

    @Override
    public void change(int position) {
        //if (this.playService.isPlaying()) {//獲取是否為播放狀態
            System.out.println("PlayActivity #100 position = " + position);
            Mp3Info mp3Info = mp3Infos.get(position);
            textView1_title.setText(mp3Info.getTitle());//設置歌名
            //獲取專輯封面圖片
            Bitmap albumBitmap = MediaUtils.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, false);
            //改變播放界面專輯封面圖片
            imageView1_ablum.setImageBitmap(albumBitmap);
            textView1_end_time.setText(MediaUtils.formatTime(mp3Info.getDuration()));//設置結束時間
            imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//設置暫停圖片
            seekBar1.setProgress(0);//設置當前進度為0
            seekBar1.setMax((int)mp3Info.getDuration());//設置進度條最大值為MP3總時間
            if (playService.isPlaying()){
                imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);
            }else {
                imageView2_play_pause.setImageResource(R.mipmap.app_music_play);
            }
        //}
    }

    //點擊事件
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.imageView2_play_pause: {//播放暫停按鈕
                if (playService.isPlaying()) {//如果是播放狀態
                    imageView2_play_pause.setImageResource(R.mipmap.app_music_play);//設置播放圖片
                    playService.pause();
                } else {
                    if (playService.isPause()) {
                        imageView2_play_pause.setImageResource(R.mipmap.app_music_pause);//設置暫停圖片
                        playService.start();//播放事件
                    } else {
                        //只有打開APP沒有點擊任何歌曲,同時,直接點擊暫停播放按鈕時.才會調用
                        playService.play(0);
                    }
                }
                break;
            }
            case R.id.imageView1_next:{//下一首按鈕
                playService.next();//下一首
                break;
            }
            case R.id.imageView3_previous:{//上一首按鈕
                playService.prev();//上一首
            }
            default:
                break;
        }
    }
}

PlayService如下:

 

 

package com.iwanghang.drmplayer;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;

import com.iwanghang.drmplayer.utils.MediaUtils;
import com.iwanghang.drmplayer.vo.Mp3Info;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 音樂播放的服務組件
 * 實現功能:
 * 播放
 * 暫停
 * 下一首
 * 上一首
 * 獲取當前歌曲的播放進度
 *
 * 需要在AndroidManifest.xml添加以下代碼:
 *
 *
 */
public class PlayService extends Service {
    private MediaPlayer mPlayer;
    private int currentPosition;//當前正在播放的歌曲的位置
    ArrayList mp3Infos;

    private MusicUpdatrListener musicUpdatrListener;

    //創建一個單實力的線程,用於更新音樂信息
    private ExecutorService es = Executors.newSingleThreadExecutor();

    private boolean isPause = false;//歌曲播放中的暫停狀態

    public boolean isPause(){
        return isPause;
    }

    public PlayService() {
    }

    public int getCurrentPosition(){
        return currentPosition;
    }

    //內部類PlayBinder實現Binder,得到當前PlayService對象
    class PlayBinder extends Binder{
        public PlayService getPlayService(){
            System.out.println("PlayService #1 " + PlayService.this);
            return PlayService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new PlayBinder();//通過PlayBinder拿到PlayService,給Activity調用
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mPlayer = new MediaPlayer();
        mp3Infos = MediaUtils.getMp3Infos(this);//獲取Mp3列表
        es.execute(updateSteatusRunnable);//更新進度值
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //回收線程
        if (es!=null && !es.isShutdown()){//當進度值等於空,並且,進度值沒有關閉
            es.shutdown();
            es = null;
        }
    }

    //利用Runnable來實現多線程
    /**
     * Runnable
     * Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable接口.
     * Runnable接口非常簡單,就定義了一個方法run(),繼承Runnable並實現這個
     * 方法就可以實現多線程了,但是這個run()方法不能自己調用,必須由系統來調用,否則就和別的方法沒有什麼區別了.
     * 好處:數據共享
     */
    Runnable updateSteatusRunnable = new Runnable() {//更新狀態
        @Override
        public void run() {
            //不斷更新進度值
            while (true){
                //音樂更新監聽不為空,並且,媒體播放不為空,並且媒體播放為播放狀態
                if(musicUpdatrListener!=null && mPlayer!=null && mPlayer.isPlaying()){
                    musicUpdatrListener.onPublish(getCurrentProgress());//獲取當前的進度值
                }
                try {
                    Thread.sleep(500);//500毫秒更新一次
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    //播放
    public void play(int position){
        if (position>=0 && position=mp3Infos.size()-1){//如果超出最大值,(因為第一首是0),說明已經是最後一首
            currentPosition = 0;//回到第一首
        }else {
            currentPosition++;//下一首
        }
        play(currentPosition);
    }

    //上一首 previous
    public void prev(){
        if (currentPosition-1<0){//如果上一首小於0,說明已經是第一首
            currentPosition = mp3Infos.size()-1;//回到最後一首
        }else {
            currentPosition--;//上一首
        }
        play(currentPosition);
    }

    //默認開始播放的方法
    public void start(){
        if (mPlayer!=null && !mPlayer.isPlaying()){//判斷當前歌曲不等於空,並且沒有在播放的狀態
            mPlayer.start();

        }
    }

    //獲取當前是否為播放狀態,提供給MyMusicListFragment的播放暫停按鈕點擊事件判斷狀態時調用
    public boolean isPlaying(){
        if (mPlayer!=null){
            return mPlayer.isPlaying();
        }
        return false;
    }

    //獲取當前的進度值
    public int getCurrentProgress(){
        if(mPlayer!=null && mPlayer.isPlaying()){//mPlayer不為空,並且,為播放狀態
            return mPlayer.getCurrentPosition();
        }
        return 0;
    }
    //getDuration 獲取文件的持續時間
    public int getDuration(){
        return mPlayer.getDuration();
    }
    //seekTo 尋找指定的時間位置
    public void seekTo(int msec){
        mPlayer.seekTo(msec);
    }

    //更新狀態的接口(PlayService的內部接口),並在BaseActivity中實現
    public interface MusicUpdatrListener{//音樂更新監聽器
        public void onPublish(int progress);//發表進度事件(更新進度條)
        public void onChange(int position); //更新歌曲位置.按鈕的狀態等信息
        //聲明MusicUpdatrListener後,添加set方法
    }

    //set方法
    public void setMusicUpdatrListener(MusicUpdatrListener musicUpdatrListener) {
        this.musicUpdatrListener = musicUpdatrListener;
    }
}

 


BaseActivity如下:
 

package com.iwanghang.drmplayer;


import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.FragmentActivity;
import android.view.View;

/**
 * Created by iwanghang on 16/4/19.
 * MainActivity繼承BaseActivity,實現APP所有綁定功能
 * 繼承後,直接調用子類方法,就可以進行綁定和解除,bindPlayService,unbindPlayService
 *
 * 模板設計模式,給FragmentActivity做了一個抽象,用來綁定服務
 *
 */
public abstract class BaseActivity extends FragmentActivity{

    protected PlayService playService;

    private boolean isBound = false;//是否已經綁定

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


    }

    //綁定Service
    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //轉換
            PlayService.PlayBinder playBinder = (PlayService.PlayBinder) service;
            //綁定播放服務
            playService = playBinder.getPlayService();
            //設置監聽器
            playService.setMusicUpdatrListener(musicUpdatrListener);
            //真正調用的是PlayActivity裡面change()
            musicUpdatrListener.onChange(playService.getCurrentPosition());
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            playService = null;
            isBound = false;
        }
    };

    //實現MusicUpdatrListener的相關方法,把PlayService.MusicUpdatrListener的具體內容,
    // 延遲到子類來具體實現(把具體的操作步驟在子類中實現)
    private PlayService.MusicUpdatrListener musicUpdatrListener = new PlayService.MusicUpdatrListener() {
        @Override
        public void onPublish(int progress) {
            publish(progress);
        }

        @Override
        public void onChange(int progress) {
            change(progress);
        }
    };
    //抽象類(子類來具體實現,用於更新UI)
    public abstract void publish(int progress);
    public abstract void change(int progress);



    //綁定服務(子類決定什麼時候調用,比如在onCreate時調用,或者在onResume,onPause時調用)
    public void bindPlayService(){
        if(!isBound) {
            Intent intent = new Intent(this, PlayService.class);
            bindService(intent, conn, Context.BIND_AUTO_CREATE);
            isBound = true;
        }
    }
    //解綁服務(子類決定什麼時候調用,比如在onCreate時調用,或者在onResume,onPause時調用)
    public void unbindPlayService(){
        if(isBound) {
            unbindService(conn);
            isBound = false;
        }
    }

    //點擊事件
    public void onClick(View v){

    }

}

 

activity_music_play.xml如下:




    
    
    

    

    

    

    

    

    




 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved