프로그램/Android

안드로이드 mp3플레어어 만들기(3.mp3 service 생성)

잡식성초보 2017. 8. 28. 14:34

이번에 작업해볼 내용은 mp3파일 플레이어를 service 구동하여 볼것입니다.

service를 이용하여 mp3파일을 실행시키기 위해서는 service 부분에서 mp3파일을 받아야 


하며 mp3플레이어인 MediaPlayer 가 service에 생성되어야 합니다.

이전 포스트에서 제가 MusicData의 소스를 공개를 안했군요..

이전 처럼 소스를 공개 안했을 상황이 생기는거 같아서 전체적으로 Notification을 이용하는 


방법 까지 다 구현하겠습니다.


1. MusicData 입니다.


버튼을 클릭하였을 경우 Intent로 서비스에 음악 데이터를 넘겨줘야하는데 차후 Notification


을 띄어서 음악을 변경하는 등의 작업을 하여야 하므로 intent값에 array를 넣어야 하는데 안


드로이드에서는 array값을 intent에 담에서 넘길때는 조금 특별한 작업을 해줘야 합니다. 그 


작업은 아래와 같습니다.



public class MusicData implements Parcelable{

    private String musicTitle;
    private String singer;
    private Uri musicImg;
    private String albumId;
    private String musicId;

    public String getMusicTitle() {
        return musicTitle;
    }

    public void setMusicTitle(String musicTitle) {
        this.musicTitle = musicTitle;
    }

    public String getSinger() {
        return singer;
    }

    public void setSinger(String singer) {
        this.singer = singer;
    }

    public Uri getMusicImg() {
        return musicImg;
    }

    public void setMusicImg(Uri musicImg) {
        this.musicImg = musicImg;
    }

    public String getAlbumId() {
        return albumId;
    }

    public void setAlbumId(String albumId) {
        this.albumId = albumId;
    }

    public String getMusicId() {
        return musicId;
    }

    public void setMusicId(String musicId) {
        this.musicId = musicId;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(musicId);
        parcel.writeString(albumId);
        parcel.writeString(musicImg.toString());
        parcel.writeString(musicTitle);
        parcel.writeString(singer);

    }

    @Override
    public int describeContents() {
        return 0;
    }

    public MusicData() {

    }

    public MusicData(Parcel in) {
        readFromParcel(in);
    }


    private void readFromParcel(Parcel in){
        musicId = in.readString();
        albumId = in.readString();
        musicImg = Uri.parse(in.readString());
        musicTitle = in.readString();
        singer = in.readString();
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        public MusicData createFromParcel(Parcel in) {
            return new MusicData(in);
        }

        public MusicData[] newArray(int size) {
            return new MusicData[size];
        }
    };
}



2. 그리고 이제 버튼을 클릭하였을경우 음악을 실행하여야 합니다.


 Activity에서 Service를 실행시켜주는 Intent만 날려주면 되는데 이전에 혹시 제가 빼먹은게 


있는거 같아서 전문 다 올리도록 하겠습니다. ListenMusic 함수가 Service 실행하는 함수입니다.




public class MusicServiceActivity extends Activity implements AdapterView.OnItemClickListener{

    private String TAG = "MusicServiceActivity";
    private Context mContext;
    private ListView musicListView;
    private MusicAdapter adapter;

    ArrayList<MusicData> list = new ArrayList<>();

    private serviceReceiver receiver;

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "MusicServiceActivity onDestroy");
        unregisterReceiver(receiver);

    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_music);
        mContext = MusicServiceActivity.this;

        init();
        getMusicData();

        IntentFilter filter = new IntentFilter(MusicService.MUSIC_SERVICE_FILTER);
        receiver = new serviceReceiver();
        registerReceiver(receiver, filter);
    }


    private void init(){

        adapter = new MusicAdapter(mContext, android.R.layout.simple_list_item_1, list);
        adapter.setMusicBtnListener(new MusicAdapter.btnClickListener() {
            @Override
            public void MusicBtnClick(int position) {
                ListenMusic(position);
            }
        });
        musicListView = findViewById(R.id.menuList);
        musicListView.setAdapter(adapter);
        musicListView.setOnItemClickListener(this);
    }

    private void getMusicData(){

        //1. 음악파일인지 아닌지, 2. 앨범 아이디, 3. 음원명, 4.가수명, 미디어 파일 아이디(?)
        String[] projection = { MediaStore.Audio.Media.IS_MUSIC, MediaStore.Audio.Media.ALBUM_ID, MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media._ID};
        ContentResolver contentResolver = mContext.getContentResolver();
        Cursor cursor = contentResolver.query(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, // content://로 시작하는 content table uri
                projection, // 어떤 column을 출력할 것인지
                null,  // 어떤 row를 출력할 것인지
                null,
                MediaStore.Audio.Media.TITLE + " ASC"); // 어떻게 정렬할 것인지

        if(cursor != null) {

            while (cursor.moveToNext()) {

                try{
                    // MediaStore.Audio.Media.IS_MUSIC 값이 1이면 mp3 음원 파일입니다.
                    // 그리고 밑에는 mp3 metadata 이미지 파일의 uri값을 얻어낸것입니다.
                    // 이렇게 얻어낸 데이터를 arraylist에 저장합니다.
                    if(cursor.getInt(0) != 0) {
                        Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
                        Uri uri = ContentUris.withAppendedId(sArtworkUri, Integer.valueOf(cursor.getString(1)));

                        MusicData data = new MusicData();
                        data.setMusicImg(uri);
                        data.setMusicTitle(cursor.getString(2));
                        data.setSinger(cursor.getString(3));
                        data.setAlbumId(cursor.getString(1));
                        data.setMusicId(cursor.getString(4));

                        list.add(data);

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                adapter.setAdapterList(list);
                            }
                        });
                    }

                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }

        cursor.close();
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {

    }

    private void ListenMusic(int position){

        Intent intent = new Intent(this, MusicService.class);
        intent.putParcelableArrayListExtra("list", list);
        intent.putExtra("position", position);
        startService(intent);
    }
}



3. 그리고 서비스 소스




public class MusicService extends Service{

    private final String TAG = "MusicService";

    private ArrayList<MusicData> list;
    private MediaPlayer mediaPlayer;
    private RemoteViews contentView;

    private NotificationManager mNoti;
    private Notification noti;

    private IntentFilter filter;
    private int nowPosotion;

    public static String MUSIC_SERVICE_FILTER = "MUSIC_SERVICE_FILTER";

    String MUSIC_PREV = "MUSIC_PREV";
    String MUSIC_NOW = "MUSIC_NOW";
    String MUSIC_NEXT = "MUSIC_NEXT";
    String MUSIC_CLOSE = "MUSIC_CLOSE";


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "MusicService onDestroy");
        unregisterReceiver(btnReceiver);
        mediaPlayer.release();
        mediaPlayer = null;
        stopForeground(true);
    }

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

        mediaPlayer = new MediaPlayer();
        list = new ArrayList<>();

        filter = new IntentFilter();
        filter.addAction(MUSIC_PREV);
        filter.addAction(MUSIC_NOW);
        filter.addAction(MUSIC_NEXT);
        filter.addAction(MUSIC_CLOSE);

        registerReceiver(btnReceiver, filter);

        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        am.requestAudioFocus(focusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

        mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
                Log.e(TAG, "mediaPlayer error i : " + i + " , i1 : " + i1);
                return false;
            }
        });


    }

    private void MusicOn(int position) {

        mediaPlayer.reset();
        Uri musicURI = Uri.withAppendedPath(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, "" + list.get(position).getMusicId());
        mediaPlayer = MediaPlayer.create(this, musicURI);
        mediaPlayer.start();

        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                Log.e(TAG, "onCompletion");

                if(list.size() == nowPosotion + 1){
                    nowPosotion = 0;
                } else{
                    nowPosotion += 1;
                }

                ChangeNotiInfomation();
                MusicOn(nowPosotion);
            }
        });
    }

    private void ChangeNotiInfomation() {

        contentView.setTextViewText(R.id.txt_title_pend, list.get(nowPosotion).getMusicTitle());
        contentView.setTextViewText(R.id.txt_singer_pend, list.get(nowPosotion).getSinger());
        contentView.setImageViewUri(R.id.img_pend, list.get(nowPosotion).getMusicImg());

        noti.bigContentView = contentView;
        startForeground(2127, noti);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind");
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        nowPosotion = intent.getExtras().getInt("position");
        Log.e(TAG, "message : " + nowPosotion);

        list = intent.getParcelableArrayListExtra("list");
        Log.e(TAG, "message : " + list.get(nowPosotion).getMusicTitle());

        Intent tent = new Intent(MUSIC_SERVICE_FILTER);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, tent, PendingIntent.FLAG_UPDATE_CURRENT);

        contentView = new RemoteViews(getPackageName(), R.layout.layout_notification);

        Intent prevIntent = new Intent(MUSIC_PREV);
        Intent nowIntent = new Intent(MUSIC_NOW);
        Intent nextIntent = new Intent(MUSIC_NEXT);
        Intent closeIntent = new Intent(MUSIC_CLOSE);

        PendingIntent pdIntentPrev = PendingIntent.getBroadcast(this, 0, prevIntent, 0);
        PendingIntent pdIntentNow = PendingIntent.getBroadcast(this, 0, nowIntent, 0);
        PendingIntent pdIntentNext = PendingIntent.getBroadcast(this, 0, nextIntent, 0);
        PendingIntent pdIntentClose = PendingIntent.getBroadcast(this, 0, closeIntent, 0);

        contentView.setTextViewText(R.id.txt_title_pend, list.get(nowPosotion).getMusicTitle());
        contentView.setTextViewText(R.id.txt_singer_pend, list.get(nowPosotion).getSinger());
        contentView.setImageViewUri(R.id.img_pend, list.get(nowPosotion).getMusicImg());

        contentView.setOnClickPendingIntent(R.id.music_prev, pdIntentPrev);
        contentView.setOnClickPendingIntent(R.id.music_now, pdIntentNow);
        contentView.setOnClickPendingIntent(R.id.music_next, pdIntentNext);
        contentView.setOnClickPendingIntent(R.id.music_close, pdIntentClose);

        Notification.Builder mBuilder = new Notification.Builder(this);

        mBuilder.setSmallIcon(R.mipmap.ic_launcher);
        mBuilder.setWhen(System.currentTimeMillis());
        mBuilder.setContentIntent(pendingIntent);
        mBuilder.setContent(contentView);
        noti = mBuilder.build();
        noti.flags = Notification.FLAG_NO_CLEAR;

        final Notification.BigPictureStyle big = new Notification.BigPictureStyle();
        


        MusicOn(nowPosotion);
//        mNoti.notify(2127, noti);
        startForeground(2127, noti);

        return START_NOT_STICKY;
    }

    BroadcastReceiver btnReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();

            if (action.equals(MUSIC_PREV)) {
                Log.e(TAG, "MUSIC_PREV");

                if (nowPosotion > 0) {

                    nowPosotion -= 1;
                    ChangeNotiInfomation();
                    MusicOn(nowPosotion);
                } else {    //다시 시작으로
                    ChangeNotiInfomation();
                    MusicOn(nowPosotion);
                }
            }

            if (action.equals(MUSIC_NOW)) {
                Log.e(TAG, "MUSIC_NOW");
            }

            if (action.equals(MUSIC_NEXT)) {
                Log.e(TAG, "MUSIC_NEXT");
                nowPosotion += 1;
                ChangeNotiInfomation();
                MusicOn(nowPosotion);
            }

            if (action.equals(MUSIC_CLOSE)) {
                Log.e(TAG, "MUSIC_CLOSE");
//                NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
//                notificationManager.cancel(2127);
                stopForeground(true);
                mediaPlayer.reset();

                Intent closeIntent = new Intent(MUSIC_SERVICE_FILTER);
                sendBroadcast(closeIntent);
            }
        }
    };

    private AudioManager.OnAudioFocusChangeListener focusChangeListener =
            new AudioManager.OnAudioFocusChangeListener() {
                public void onAudioFocusChange(int focusChange) {
                    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                    switch (focusChange) {

                        case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK):
                            Log.e(TAG, "OnAudioFocusChangeListener AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK");
                            break;
                        case (AudioManager.AUDIOFOCUS_LOSS_TRANSIENT):
                            Log.e(TAG, "OnAudioFocusChangeListener AUDIOFOCUS_LOSS_TRANSIENT");
                            break;

                        case (AudioManager.AUDIOFOCUS_LOSS):
                            Log.e(TAG, "OnAudioFocusChangeListener AUDIOFOCUS_LOSS");

                            mediaPlayer.stop();
                            contentView.setImageViewResource(R.id.music_now, R.drawable.play_pause);

                            noti.bigContentView = contentView;
                            startForeground(2127, noti);

                            break;

                        case (AudioManager.AUDIOFOCUS_GAIN):
                            Log.e(TAG, "OnAudioFocusChangeListener AUDIOFOCUS_GAIN");
                            break;
                        default:
                            break;
                    }
                }
            };

//    @Override
//    public void onCompletion(MediaPlayer mediaPlayer) {
//
//        Log.e(TAG, "onCompletion");
//
//        if(list.size() == nowPosotion + 1){
//            nowPosotion = 0;
//        } else{
//            nowPosotion += 1;
//        }
//
//        ChangeNotiInfomation();
//        MusicOn(nowPosotion);
//    }


    @Override
    public void onTaskRemoved(Intent rootIntent) {
        super.onTaskRemoved(rootIntent);
        Log.e(TAG, "onTaskRemoved");
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.e(TAG, "onConfigurationChanged");
    }

    @Override
    public boolean onUnbind(Intent intent) {

        Log.e(TAG, "onUnbind");
        return super.onUnbind(intent);
    }
}




<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="100dp" android:layout_centerVertical="true"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:layout_centerVertical="true" android:layout_marginLeft="20dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:text="TestApp" android:textColor="#1266FF"/> <TextView android:id="@+id/txt_title_pend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp" android:textSize="15sp" android:text="test" android:textStyle="bold" /> <TextView android:id="@+id/txt_singer_pend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="3dp" android:textSize="12sp" android:text="test" /> </LinearLayout> <ImageView android:id="@+id/img_pend" android:layout_width="45dp" android:layout_height="45dp" android:layout_marginRight="20dp" android:layout_centerVertical="true" android:layout_alignParentRight="true"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="35dp" android:orientation="horizontal" android:layout_toLeftOf="@id/img_pend" android:layout_marginRight="15dp" android:layout_centerVertical="true" android:gravity="center_vertical"> <ImageButton android:id="@+id/music_prev" android:layout_width="16dp" android:layout_height="16dp" android:layout_marginRight="10dp" android:background="@drawable/play_prev" /> <ImageButton android:id="@+id/music_now" android:layout_width="16dp" android:layout_height="16dp" android:layout_marginRight="10dp" android:background="@drawable/play_pause" /> <ImageButton android:id="@+id/music_next" android:layout_width="16dp" android:layout_height="16dp" android:layout_marginRight="10dp" android:background="@drawable/play_next" /> <ImageButton android:id="@+id/music_close" android:layout_width="16dp" android:layout_height="16dp" android:background="@drawable/play_close" /> </LinearLayout> </RelativeLayout>



안드로이드 Manifest에서 receiver와 service 등록 잊지마세요.



<receiver android:name=".Screen.ScreenReceiver" />
<service
      android:name=".music.MusicService"
      android:enabled="true">
      <intent-filter>
            <action android:name="MUSIC_SERVICE_FILTER"/>
      </intent-filter>
</service>


반응형