安卓Service實現通知欄音樂播放器,切換歌曲,類似QQ音樂

引言:
這樣的一個音樂播放器,用到了安卓四大組件的其中三個,等於說是一個比較綜合性的小功能。實現方法其實有很多,我這裏給出自己的方法,不喜勿噴。
需求分析
1.音樂播放器,那我們需要一個幫助類,來構建單例音樂播放器對象:

package com.example.jackandrose.entities;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;

import java.io.IOException;

public class MediaHelper {
    private static MediaHelper instance;
    private Context mContext;
    private MediaPlayer mMediaPlayer;
    private OnMediaHelperListener mOnMediaHelperListener;
    private int mResID=-5;

    public void setmOnMediaHelperListener(OnMediaHelperListener mOnMediaHelperListener) {
        this.mOnMediaHelperListener = mOnMediaHelperListener;
    }

    public static MediaHelper getInstance(Context context) {
        if(instance==null){
            synchronized (MediaHelper.class){
                if(instance==null){
                    instance=new MediaHelper(context);
                }
            }
        }
        return instance;
    }

    private MediaHelper(Context context){
        mContext=context;
        mMediaPlayer=new MediaPlayer();
    }

    /**
     * 當播放本地uri中音時調用
     * @param path
     */
    public void setPath(String path){
        if(mMediaPlayer.isPlaying()){
            mMediaPlayer.reset();
        }
        try {
            mMediaPlayer.setDataSource(mContext, Uri.parse(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        mMediaPlayer.prepareAsync();
        mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                if(mOnMediaHelperListener !=null){
                    mOnMediaHelperListener.onPrepared(mp);
                }
            }
        });
        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if(mOnMediaHelperListener !=null){
                    mOnMediaHelperListener.onPauseState();
                }
            }
        });
    }

    /**
     * 當調用raw下的文件時使用
     * @param resid
     */
    public void setRawFile(int resid){
        if(resid==mResID&&mResID!=-5){
            //相同音樂id或者且不是第一次播放,就直接返回
            return;
        }
        //mOnInitMusicListener.initMode();
        mResID=resid;
        final AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(resid);
        try {
            mMediaPlayer.reset();
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            mMediaPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                if(mOnMediaHelperListener !=null){
                    mOnMediaHelperListener.onPrepared(mp);
                    try {
                        afd.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                if(mOnMediaHelperListener !=null){
                    mOnMediaHelperListener.onPauseState();
                }
            }
        });
    }

    public void start(){
        if(mMediaPlayer.isPlaying()){
            return;
        }
        mMediaPlayer.start();
        if(mOnMediaHelperListener!=null){
            mOnMediaHelperListener.onPlayingState();
        }

    }

    public void pause(){
        if(!mMediaPlayer.isPlaying()){
            return;
        }
        mMediaPlayer.pause();
        if(mOnMediaHelperListener!=null){
            mOnMediaHelperListener.onPauseState();
        }
    }

    public boolean isPlaying(){
        if(mMediaPlayer!=null&&mMediaPlayer.isPlaying()){
            return true;
        }
        return false;
    }

    public int getCurrentPosition(){
        return mMediaPlayer.getCurrentPosition();
    }

    public int getDuration(){
        return mMediaPlayer.getDuration();
    }

    public void seekTo(int progress){
        mMediaPlayer.seekTo(progress);
    }

    public interface OnMediaHelperListener {
        //音樂準備好之後調用
        void onPrepared(MediaPlayer mp);
        //音樂暫停狀態
        void onPauseState();
        //音樂播放狀態
        void onPlayingState();
    }

}

2.首先,要實現播放器顯示在通知欄裏面,毫無疑問,要創建通知,以前臺服務的形式顯示
<1>創建通知:

package com.example.jackandrose.entities;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

import androidx.core.app.NotificationCompat;

import com.example.jackandrose.R;
import com.example.jackandrose.activities.Main2Activity;
import com.example.jackandrose.activities.MainActivity;


public class NotifyHelper {
    private static NotifyHelper instance;
    private Context mContext;

    public static NotifyHelper getInstance(Context context) {
        if(instance==null){
            instance=new NotifyHelper(context);
        }
        return instance;
    }

    private NotifyHelper(Context context){
        mContext=context;
    }

    public void CreateChannel(String channel_id,CharSequence channel_name,String description){
        //8.0以上版本通知適配
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel notificationChannel=new NotificationChannel(channel_id,channel_name, NotificationManager.IMPORTANCE_HIGH);
            notificationChannel.setDescription(description);
            NotificationManager notificationManager=mContext.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(notificationChannel);
        }
    }

    /**
     * 返回一個前臺通知
     * @param channel_id  通知渠道id,注意8.0創建通知的時候渠道id與此要匹配
     * @param musicPicture 數據對象
     * @param remoteViews 自定義通知樣式的對象,但是與View不同,不提供findViewById方法,詳細建議看看源碼和官方文檔
     * @return
     */

    public Notification createForeNotification(String channel_id, MusicPicture musicPicture,RemoteViews remoteViews){
        Intent intent=new Intent(mContext, MainActivity.class);
        PendingIntent mainIntent=PendingIntent.getActivity(mContext,0,intent,0);
        NotificationCompat.Builder builder=new NotificationCompat.Builder(mContext,channel_id)
                .setSmallIcon(R.mipmap.qqyinyue)
                .setStyle(new NotificationCompat.DecoratedCustomViewStyle()) 
                .setCustomBigContentView(remoteViews)
                .setContentIntent(mainIntent)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);
        return builder.build();
    }
}

細心的朋友肯定發現了,我構建通知的時候picture對象沒有使用到,我也不想改了,就放着吧~
需要注意的是,RemoteViews不支持部分佈局和控件,ConstraintLayout,用於顯示音樂進度的SeekBar,還有各種第三方庫,比如CircleImageView,這些都不被支持,反正我剛開始寫出來的佈局,通知界面便沒有正確顯示。
<2>佈局代碼:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cl_music_player"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/myActionBarColor"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_music_icon"
        android:layout_width="@dimen/myBigMusicIconSize"
        android:layout_height="@dimen/myBigMusicIconSize"
        android:layout_gravity="center"
        android:scaleType="fitXY"
        android:layout_marginLeft="16dp"
        android:src="@mipmap/qqyinyue" />

    <LinearLayout
        android:orientation="vertical"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content">
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            >
            <ImageView
                android:id="@+id/iv_music_last_song"
                android:layout_width="@dimen/myMusicIconSize"
                android:layout_height="@dimen/myMusicIconSize"
                android:layout_margin="16dp"
                android:layout_gravity="left|center_vertical"
                android:src="@mipmap/music_last" />

            <ImageView
                android:id="@+id/iv_music_play"
                android:layout_width="@dimen/myIconSize"
                android:layout_height="@dimen/myIconSize"
                android:layout_margin="16dp"
                android:src="@mipmap/play_music"
                android:layout_gravity="center"/>

            <ImageView
                android:id="@+id/iv_music_next_song"
                android:layout_width="@dimen/myMusicIconSize"
                android:layout_height="@dimen/myMusicIconSize"
                android:layout_margin="16dp"
                android:src="@mipmap/music_next"
                android:layout_gravity="right|center_vertical"/>
        </FrameLayout>
    </LinearLayout>
</LinearLayout>

<3>創建主服務,用於顯示播放器和控制整個音樂播放的服務,並且這裏面實現了音樂播放幫助類的外放接口:

package com.example.jackandrose.services;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.widget.RemoteViews;

import com.example.jackandrose.R;

import com.example.jackandrose.broadcasts.MyBroadCastReceiver;
import com.example.jackandrose.entities.MediaHelper;
import com.example.jackandrose.entities.MusicPicture;
import com.example.jackandrose.entities.NotifyHelper;

public class MyService extends Service {

    /**
     * 此服務,用於展示音樂播放器,並實現音樂播放
     * 在此說明一下我們音樂播放器的實現
     * 1.  整體界面使用通知實現前臺服務
     * 2. 上面的圖片按鈕操作選擇了另外的Service和BroadCast
     * 3. 操作方面其實後臺的話,服務和廣播都是不錯的選擇
     * 4. 切換歌曲我選擇了廣播,暫停和繼續播放我選擇了另外的服務
     */

    private static final String CHANNEL_ID = "music_channel_id";
    private static final String CHANNEL_NAME = "music_channel_name";
    private static final String CHANNEL_DESCRIPTION = "music_channel_description";
    private static final int NOTIFY_ID = 0x1;
    private NotifyHelper mNotifyHelper;
    private MediaHelper mMediaHelper;
    private RemoteViews notifyLayout;
    private MyBroadCastReceiver mMyBroadCastReceiver;
    private static final boolean MODE_PLAY = true;
    private static final boolean MODE_PAUSE = false;
    private boolean flag;

    @Override
    public void onCreate() {
        super.onCreate();
        mMediaHelper = MediaHelper.getInstance(this);
        mNotifyHelper = NotifyHelper.getInstance(this);
        notifyLayout = new RemoteViews(MyService.this.getPackageName(), R.layout.player_layout);
        mMyBroadCastReceiver=MyBroadCastReceiver.getInstance();
        flag=MODE_PAUSE;
        mRegistBroadCast();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mMyBroadCastReceiver);
    }

    /**
     * 動態註冊廣播,因爲8.0版本以後靜態註冊可能不起作用
     */

    private void mRegistBroadCast() {
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("com.example.jackandrose.broadcasts.PLAY_LAST");
        intentFilter.addAction("com.example.jackandrose.broadcasts.PLAY_NEXT");
        registerReceiver(mMyBroadCastReceiver,intentFilter);
    }

    public MyService() {

    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return new MyBinder();
    }

    public class MyBinder extends Binder {

        MyBinder() {
            super();
        }

        public MyService getService() {
            return MyService.this;
        }

        public void setMusic(final MusicPicture picture) {
            mMediaHelper.setmOnMediaHelperListener(new MediaHelper.OnMediaHelperListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    flag=MODE_PAUSE;
                    playMusicState(picture);
                    mMediaHelper.start();
                }

                @Override
                public void onPauseState() {
                    pauseMusicState(picture);
                }

                @Override
                public void onPlayingState() {
                    playMusicState(picture);
                }

            });
            changeMusic();
            mMediaHelper.setRawFile(picture.getPic_resource());
        }

        private void changeMusic() {
            /**
             * 發送廣播,進行切歌到上一首操作
             */
            Intent lastIntent=new Intent("com.example.jackandrose.broadcasts.PLAY_LAST");
            PendingIntent lastPendingIntent=PendingIntent.getBroadcast(MyService.this,0,lastIntent,0);
            notifyLayout.setOnClickPendingIntent(R.id.iv_music_last_song,lastPendingIntent);
            /**
             * 發送廣播,進行切歌到下一首操作
             */
            Intent nextIntent=new Intent("com.example.jackandrose.broadcasts.PLAY_NEXT");
            PendingIntent nextPendingIntent=PendingIntent.getBroadcast(MyService.this,0,nextIntent,0);
            notifyLayout.setOnClickPendingIntent(R.id.iv_music_next_song,nextPendingIntent);

        }

        /**
         * 更改了相關設置,比如notifyLayout佈局顯示之後,需要重新發送前臺通知來更新UI
         * 太坑了,居然是這樣的
         *  此外,由於我們是顯示成一個播放器,因此通知id,使用固定id,就可以保證每次更新之後是同一個通知。
         * @param picture 設置播放器圖標爲指定音樂圖標,此對象屬於MVC開發模式的model層數據
         */
        private void mstartForeground(MusicPicture picture) {
            mNotifyHelper.CreateChannel(CHANNEL_ID, CHANNEL_NAME, CHANNEL_DESCRIPTION);
            final Notification notification = mNotifyHelper.createForeNotification(CHANNEL_ID, picture, notifyLayout);
            startForeground(NOTIFY_ID, notification);
        }

        /**
         * 處於播放狀態下的音樂應該具有的一些配置
         * @param picture
         */
        private void playMusicState(MusicPicture picture) {
            if(flag==MODE_PLAY) return;
            flag=MODE_PLAY;
            Intent pauseIntent=new Intent(MyService.this,PauseService.class);
            PendingIntent pausePendingIntent=PendingIntent.getService(MyService.this,0,pauseIntent,0);
            notifyLayout.setOnClickPendingIntent(R.id.iv_music_play,pausePendingIntent);
            notifyLayout.setImageViewResource(R.id.iv_music_icon, picture.getPic_id());
            notifyLayout.setImageViewResource(R.id.iv_music_play, R.mipmap.pause_music);
            mstartForeground(picture);
        }

        /**
         * 處於暫停狀態下的音樂應該具有的一些配置
         * @param picture
         */

        private void pauseMusicState(MusicPicture picture) {
            if(flag==MODE_PAUSE) return;
            flag=MODE_PAUSE;
            Intent playIntent=new Intent(MyService.this,PlayService.class);
            PendingIntent playPendingIntent=PendingIntent.getService(MyService.this,0,playIntent,0);
            notifyLayout.setOnClickPendingIntent(R.id.iv_music_play,playPendingIntent);
            notifyLayout.setImageViewResource(R.id.iv_music_icon, picture.getPic_id());
            notifyLayout.setImageViewResource(R.id.iv_music_play, R.mipmap.play_music);
            mstartForeground(picture);
        }

    }
}

注意看代碼註釋,我覺得蠻清晰的,該說明的基本都說了哦~
特別注意一下我說坑的地方,就是更新通知欄播放器上面控件設置,必須在通知發送前實現,故我採用更新界面之後,重新發送相同id的一條通知!!!
3.好了,接下來,我們來實現兩個服務,和一個廣播接收器:
<1>播放與暫停服務:

package com.example.jackandrose.services;

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

import com.example.jackandrose.entities.MediaHelper;

public class PlayService extends Service {
    /**
     * 用於使音樂繼續播放的服務
     */

    private MediaHelper mMediaHelper;

    public PlayService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        mMediaHelper=MediaHelper.getInstance(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mMediaHelper.start();
        stopSelf();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

package com.example.jackandrose.services;

import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;


import com.example.jackandrose.entities.MediaHelper;

public class PauseService extends Service {
    /**
     * 用於使音樂暫停的服務
     */
    private MediaHelper mMediaHelper;

    public PauseService() {

    }

    @Override
    public void onCreate() {
        super.onCreate();
        mMediaHelper=MediaHelper.getInstance(this);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        mMediaHelper.pause();
        stopSelf();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

這個時候,你就知道我們將音樂播放幫助類接口外放的原因了。我們在主服務裏面實現了接口,即實現了播放和暫停狀態下的UI界面,所以我們在服務裏面只需要放心大膽的使用音樂幫助類的暫停和播放方法就可以了,音樂它們會調用外放的接口方法。
<2>切換歌曲的廣播,其實播放和暫停完全也可以用廣播實現,但是我爲了看起來更加多元化,哈哈哈:

package com.example.jackandrose.broadcasts;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class MyBroadCastReceiver extends BroadcastReceiver {
    /**
     * 切換歌曲的廣播,這裏仍採用單例模式。
     * 原因是我們要將切換歌曲的接口外放到MusAdapter
     */

    private static MyBroadCastReceiver instance;
    private static final String PLAY_LAST="com.example.jackandrose.broadcasts.PLAY_LAST";
    private static final String PLAY_NEXT="com.example.jackandrose.broadcasts.PLAY_NEXT";
    private MyBroadListner mMyBroadListner;

    public static MyBroadCastReceiver getInstance() {
        if(instance==null){
            instance=new MyBroadCastReceiver();
        }
        return instance;
    }

    public void setmMyBroadListner(MyBroadListner mMyBroadListner) {
        this.mMyBroadListner = mMyBroadListner;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction()==null){
            Log.w("MyBroadCastReceiver","yes");
        }else{
            Log.w("MyBroadCastReceiver","no");
        }

        if(PLAY_LAST.equals(intent.getAction())){
            Toast.makeText(context, "即將切換至上一首,若切換失敗,請回到界面點擊音樂實現切換", Toast.LENGTH_LONG).show();
            if(mMyBroadListner!=null){
                mMyBroadListner.playLast();
            }

        }else if(PLAY_NEXT.equals(intent.getAction())){
            Toast.makeText(context, "即將切換至下一首,若切換失敗,請回到界面點擊音樂實現切換", Toast.LENGTH_LONG).show();
            if(mMyBroadListner!=null){
                mMyBroadListner.playNext();
            }
        }
    }

    /**
     * 定義外放接口,在MusAdapter類中我進行了實現
     */
    public interface MyBroadListner{
        void playLast();
        void playNext();
    }
}

注意一下,廣播這個東西,8.0以上也有變化,靜態註冊可能不起作用,因此我在MyService的代碼裏進行了動態註冊,爲了保險起見,我們靜態也加上:

        <receiver android:name=".broadcasts.MyBroadCastReceiver">
            <intent-filter>
                <action android:name="com.example.jackandrose.broadcasts.PLAY_LAST" />
                <action android:name="com.example.jackandrose.broadcasts.PLAY_NEXT" />
            </intent-filter>
        </receiver>

4.廣播接收器的代碼註釋提到了MusAdapter,沒錯了,這裏便是音樂播放的啓動器,我們是單擊RecyclerView單個條目實現播放的,並設置選中條目,單擊選中條目則不會播放。
實現廣播接收器的外放接口!!!
代碼還是給出來吧:

package com.example.jackandrose.adapters;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.IBinder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.example.jackandrose.R;
import com.example.jackandrose.broadcasts.MyBroadCastReceiver;
import com.example.jackandrose.entities.MusicPicture;
import com.example.jackandrose.services.MyService;

import java.util.ArrayList;

public class MusAdapter extends RecyclerView.Adapter<MusAdapter.ViewHolder> {

    private static final String TAG = "MusAdapter";
    private ArrayList<MusicPicture> myPictures;
    private Context mContext;
    private int selectedPosition = -5;
    private int mResID=-5;
    private MyService.MyBinder mMyBinder;
    private MyService mMyService;
    private boolean isBind;
    private Intent mServiceIntent;
    private MusicPicture mMusicPicture;
    private MyBroadCastReceiver mMyBroadCastReceiver;

    class ViewHolder extends RecyclerView.ViewHolder {
        ImageView picImg;
        TextView picText;
        LinearLayout box;
        int d_id; //音樂圖片id
        int d_resource;  //音樂資源id
        View view;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            picImg = (ImageView) itemView.findViewById(R.id.pic_image);
            picText = (TextView) itemView.findViewById(R.id.pic_text);
            box = itemView.findViewById(R.id.item_box);
            view = itemView;
        }
    }

    public MusAdapter(ArrayList<MusicPicture> pictures,Context context) {
        myPictures = pictures;
        mContext=context;
        mMyBroadCastReceiver=MyBroadCastReceiver.getInstance();
        isBind=false;
    }

    private void setMyBroadCastListener() {
        /**
         * 此處仍然來實現單例對象的接口對象
         * 即實現歌曲的切換,實現廣播接收器的外放接口
         */
        mMyBroadCastReceiver.setmMyBroadListner(new MyBroadCastReceiver.MyBroadListner() {
            @Override
            public void playLast() {
                MusAdapter.this.playLast();
            }

            @Override
            public void playNext() {
                MusAdapter.this.playNext();
            }
        });
    }

    private void playLast() {
        if (selectedPosition > 0) {
            setSelectedIndex(selectedPosition - 1);
        }
    }

    private void playNext() {
        if (selectedPosition < getItemCount() - 1) {
            setSelectedIndex(selectedPosition + 1);
        }
    }

    private void stateChange(ViewHolder holder, int position,MusicPicture picture) {
        if (selectedPosition == position) {
            setMyBroadCastListener();
            //不管怎麼樣,先把狀態改變效果展示出來
            int color = holder.view.getContext().getResources().getColor(R.color.myActionBarColor);
            holder.box.setBackgroundColor(color);
            holder.picText.setTextColor(Color.WHITE);

            mMusicPicture =picture;

            if(picture.getPic_resource()==mResID&&mResID!=-5){
                //相同音樂id或者且不是第一次播放,就直接返回
                return;
            }

            mResID=picture.getPic_resource();

            //啓動服務來播放
            if(mServiceIntent==null){
                mServiceIntent=new Intent(mContext,MyService.class);
                mContext.startService(mServiceIntent);
            }

            //每次切歌需要重新綁定服務
            destroy();
            if(!isBind){
                mContext.bindService(mServiceIntent,connection,Context.BIND_AUTO_CREATE);
                isBind=true;
            }
        } else {
            holder.box.setBackgroundColor(Color.WHITE);
            holder.picText.setTextColor(Color.BLACK);
            //因爲我們從始至終只有一個顯示圖片的imageview,所以不應該寫下面這行代碼
        }
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
        MusicPicture musicPicture = myPictures.get(position);
        holder.picImg.setImageResource(musicPicture.getPic_id());
        holder.picText.setText(musicPicture.getPic_name());
        holder.d_id = musicPicture.getPic_id();
        holder.d_resource = musicPicture.getPic_resource();
        setClick(holder, position);
        stateChange(holder, position,musicPicture);
    }

    @Override
    public int getItemCount() {
        return myPictures.size();
    }

    private void setClick(ViewHolder holder, final int position) {
        holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setSelectedIndex(position);
            }
        });
    }

    private void setSelectedIndex(int position) {
        selectedPosition = position;
        notifyItemChanged(position);
        notifyDataSetChanged();
    }

    private void destroy(){
        if(isBind){
            mContext.unbindService(connection);
            isBind=false;
        }
    }

    private ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMyBinder= (MyService.MyBinder) service;
            mMyService=mMyBinder.getService();
            mMyBinder.setMusic(mMusicPicture);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };
}

MusicPicture類就不再展示了,就是標準的數據類,包含get和set方法~
寫的有些亂,不好的地方提提意見,不要噴我,畢竟我還是個新手,謝謝。
5.效果圖展示:
<1>音樂條目界面:
在這裏插入圖片描述
<2>音樂播放界面:
在這裏插入圖片描述
6.好了,到這裏就結束了,不過其實bug就是退出界面後,切歌功能實效,其實不難理解爲什麼,但是實在不知道如何解決,或者說直接換一種實現,避免這個問題。

能看完的都太厲害了…能堅持看完的兄弟,如果覺得我寫的也不是特別差的話,動動小手點個讚唄。覺得我寫的存在問題的,歡迎提出來,我也特別希望有一些改進的建議,謝謝觀看!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章