마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

뮤직플레이어 앱을 만들고있습니다. service관련 질문드립니다..

0 추천
뮤직플레이어 앱을 만들고있습니다.

service를 실행하고 바인딩도 했습니다.

service에 mediaPlayer를 통해 음악을 재생하고, notification을 띄우고 startForground도 실행하여서

 

음악이 재생될때 앱을 홈버튼옆에 앱리스트에서 종료해도 노래가 나오게는 했습니다.

 

문제는 앱을 다시시작했을 때 종료전에 실행시킨 mediaPlayer객체에 접근을 하고싶은데

어떻게 해야할지 모르겠습니디다.

 

이것을 해결하기위해서 ActivityManager가 사용자가만든 service정보를 가져올수있다고 알게되어 해봣는데

 ActivityManager를 통해서 service를 가져올수있나 싶었는데 정보만 가져올수있고, 객체자체는 주지 않더군요....

 

앱스토에어 출시된 음악재생앱들은 제가 구현하고자 하는 기능들이 구현되있던데

어떻게 해야할까요 제발 힌트라도 주시면 정말 감사하겠습니다.
사란 (810 포인트) 님이 2019년 4월 9일 질문

2개의 답변

+1 추천
 
채택된 답변

제대로 구현하는 방법은 있겠지만 

저같은 경우는 MyApplication을 사용해서 전역변수식으로 사용하는 방법을 사용해보고 있습니다.

==================================================================

MyApplication.java

public static ArrayList<MediaPlayer> arr_player = new ArrayList<>();

==================================================================

알고계신 부분이시겠지만 링크해둡니다, 사용법에 따라 메모리 누수의 원인이 되기도 하지만

잘 사용하면 매우 편리합니다. 안드로이드 OS 버젼이 올라갈수록 보안 이슈나 엄격해진 권한 관리로 

사용자개발 앱의 제한이 워낙 심해지다보니 여러모로 고민해볼것들이 많아지네요.

MyApplication 사용법

http://theeye.pe.kr/archives/1314

포스코 (1,490 포인트) 님이 2019년 4월 9일 답변
사란님이 2019년 4월 10일 채택됨
먼저 답변감사합니다.
말씀해주신방법은 앱에 전역변수영역을 쓰는것입니다.
앱이 살아있는한 모든 엑티비티에서 계속 접근이가능하고 공유한데이터를 쓸수있죠.. 하지만 앱이 완전종료됬을때는 전역변수라고 해도 날라갑니다.
서비스는 앱이 종료되도 안드로이드 시스템 어디가에 올라가서 실행됩니다.
거기를 접근이 가능해야합니다 ㅠ...
혹시 제가 잘못알고있나해서 이미 해봣지만 전역변수에 미디어 객체를 넣어서 해봣으나 원하는 결과를 얻지못했습니다. 답변감사합니다...ㅠ
제가 말을 좀 잘못쓴거같습니다. 말씀하신대로 startForeground로 실행되고있는 서비스가 참조하는 전역변수는 살아있는건 맞습니다 일단 죄송합니다 ㅠ..
그런데 그렇다면 startForeground로 실행하여 연결되있는 이 전역변수가있는데,
앱을 다시실행하여 살아있는 전역변수영역에 어떻게 접근할수있는지.. 궁금합니다..
이 살아있는 전역변수에 접근을 하고싶은데 그걸 어떻게 해야할지 모르겠습니다. ..
MyApplication.java(정의하신 클래스 이름)에 변수가 static 으로 선언 되어 있으므로

클래스이름.변수이름

MyApplication.arr_player  로 사용하시면 끝입니다

 for(MediaPlayer item : arr_player){
            try {
                if (item != null) {
                    item.stop();
                    item.release();
                }
            }
            catch (Exception k){
                //Log.e("에러","으아아아");
            }
        }
        arr_player.clear();
해봣는데 다른 같은 변수로 취급을 합니다. 껏다킨거라서 다른 변수로 취급되서..
A앱에 a전역변수 이고 만약 가상에 메모리주소가 1111번지이면, A앱에 a에 1111에 미디어객체를 넣어서 재생합니다. 이러면 1111에 미디어객체가 노래를 재생하고있는데, 앱을끕니다. a와 1111은 연결은 끊깁니다. 하지만 startforground해서 1111은 살아있습니다. 노래도나옵니다.

A앱을 다시킵니다 a는 연결된에가 메모리주소가 없습니다. 그런데 111과 연결되있으면 상관이없는데 다른 메모리주소에 할당됩니다. 그래서 1111에 연결된 미디어를 컨트롤 못합니다.. 제가 이해한건이건데 아닌건가요..?..
MainAcitivity에서 직접 접근하시려면 말씀하신 이슈가 있겠지요.

Service 클래스 내에서 객체를 처리하면 어떨까요?

[MainActivity.java]

//선언
Intent service;
SongService services;
ServiceConnection connection;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent service;
        SongService services;
        service = new Intent(this, SongService.class);
        connection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                SongService.MyBinder binderr = (SongService.MyBinder) service;
                services = binderr.getServiceSystem();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
/* ......................... */

btn_stop.setOnClickListener(new View.OnClickListener() {
    //노래 종료
   unbindService(connection);
   stopService(service);
}

[SongService.java]
public void stopSong(){
    for(MediaPlayer item : arr_player){
        try {
            if (item != null) {
                item.stop();
                item.release();
            }
        }
        catch (Exception k){
            //Log.e("에러-스톱","으아아아");
        }
    }
    arr_player.clear();
}


protected class MyBinder extends Binder
    {
        public SongService getServiceSystem()
        {
            return SongService.this;
        }
    }

앱이 재실행되었을때 실행중인 서비스를 접근해서
해당 서비스의 메소드를 호출하고
그 안에서 해당 변수를 조작한다면?

명쾌하게 설명을 못드려 죄송하네요. ^^;
제 질문의 내용이 그거였습니다 ㅋㅋ
앱이 재 실행되었을때 실행중인 서비스에 접근!!
그 방법을 모르겠습니다.. 바인딩을 통해해도 재실하면 새로운 서비스에 바인딩을 해버립니다 ㅠㅠㅠㅠㅠ 여기까지 답글해주신것도 너무 감사합니다 ㅠ..
ServiceConnection이 실행중인 서비스에 연결하는 부분입니다,
이미... 저도 해놨다는 ㅠㅠ..
class BaseApplication : Application(){

    val BC_READY_FOR_BOTTOM_PLAYER = "com.example.musicplayer.ready_for_bottom_player"
    val BC_BOTTOM_ICON_PUASE = "com.example.musicplayer.bottom_icon_puase"
    val BC_BOTTOM_ICON_PLAY = "com.example.musicplayer.bottom_icon_play"

    lateinit var mpService : MusicPlayerService
    var mBound : Boolean = false

    val mConnection : ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            Log.i("TEST","onServiceConnected")
            val mpBinder : MusicPlayerService.MusicPlayerBinder = service as MusicPlayerService.MusicPlayerBinder
            mpService = mpBinder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            Log.i("TEST","onServiceDisconnected")
            mBound = false
        }
    }

}
앱을 재실행할때 MainActivity에서 재생중인 음악을 Stop해서

unbindService(connection);
 stopService(service);

를 해도 기존 실행중인 노래가 종료가 되지 않던가요?

코틀린으로 작성하고 계시군요 ㅎㅎ 저도 언젠가 넘어가야하는데

게을러서... ㅠ,ㅠ
재실행해서 다시시작하는 순간 접근할수없으니까 stop도 안되요 ㅠ..
물론! 앱을끌때 unbind, stop은 잘되요 ㅎ;;

코틀린 많이 헷갈리는데 점점 좋아지는것 같아요 ㅋ;;; 소스가 짧아지거나.. 생성자 시점을 조절이 가능한다던가,, 널포인트 신경안쓰게 선언해버린다던가.등등...이건 여담이였습니다..
저같은 경우는 MainActivity에서 버튼을 스톱 또는 시작을 누르면

서비스 클래스 내에서
1) public void onDestroy()에서 미디어 객체를 다루는 stopSong();을 호출하고

2) onStartCommand에서 startSong을 호출합니다.
@Override public int onStartCommand(Intent intent, int flags, int startId) {
         startSong();
        return START_STICKY;
    }


기존 재생중인 음악을 종료하는 부분이
정상적으로 동작되는지부터 점검해보시면 좋겠네요.
포스코님 늦게나마 감사말씀드립니다.
application에 MediaPlayer를 등록해놓고 하니 됬습니다.
문제는 제가 코틀린을 이용하다보니 초기화 선언에서 혼동이 있었고
그로인해서 안됬던것 이였습니다. 감사하고 덕분에 앱을 완성할 수 있을 것같습니다. 다시한번 감사드립니다.
0 추천
안녕하세요

로컬에 있는 파일을 Play하는 것인가요?

그럼 sharedPreference에 Play중이었던 곡 이름(혹은 id..)와 재생정보(Play되었던 위치)를 저장하고 구동 시 이 정

보를 통해 다시 플레이 하면 되지 않을까요?
지나가는 나그네 님이 2019년 4월 9일 답변
먼저 답변감사드립니다.
로컬에있는 파일 맞습니다.
설명이 조금 부족했던 것같습니다 . 노래가 이미 흘러나오고있고, 그상태에서 앱을 중지해도 노래는 계속나옵니다. 그상태에서 앱을 실행했을때 지금 나오고 있는 노래에 mediaplay객체를 컨틀롤 할수(노래를 중단한다던가, 현재 나오는 지점을 알아낸다던가..) 있어야합니다. 말씀해주신대로 하면 똑같은 id라도 다른객체로 인식되서 이미 나오던 나오는 노래는 계속나오고, 새로 시작할 노래는 새롭게 되어 노래가 중복되어서 흘러나옵니다 ㅠ.. 그래도 의견감사합니다.
혹시모르니까 말씀해주신방법도 적어놧다가 구현해보겠습니다 ㅠ.
음.. 다시보니. Notification이 살아있고 노래가 Play중인걸로 봐서는 service가 살아 있는 것 같은데, service에 mediaPlayer 관련 정보가 없는 상태 인가요????
앱을 완전종료해도 service가 실행되있는 상황일때, 다시 앱을 실행했을 때 종료전실행 했던 service에 접근을 어떻게하냐가 질문내용이였습니다. (말을 잘 정리를 못해서 죄송합니다.) 물론 service를 접근하기위해 bind하긴합니다. 하지만 종료와 함께 바인딩은 풀리기 때문에 질문을 하게되었습니다....

결론적으로 오늘 해결했습니다. 포스코님 말씀처럼 application 클래스에 미디어 객체를 올려두고, 서비스는 앱실행때마다 새로 실행시키지만, 서비스에서 호출하는 미디어객체는 application에 등록해서 사용했습니다.

다시한번 정리하자면 application, service 이두가지의 생명주기를 알아야 해결가능한 문제였습니다.. 댓글과관심에 감사드립니다..
...