본문 바로가기
프로그램/Android

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

by 고래밥89 2017. 8. 28.
반응형

이번에 작업해볼 내용은 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>


반응형