안드로이드 4대 컴포넌트 - Service_3(bound service?)

권민주·2024년 1월 11일

안드로이드

목록 보기
5/23
post-thumbnail

안드로이드에는 필수적인 앱 기본 구성 요소로 activity, service, broadcast receiver, content provider 4가지를 가집니다. 이전 글에 이어 service의 bound service에 대해 설명하겠습니다. 이 포스트로 service에 대한 설명을 마칩니다


5. Bound service란

1) bound service?

Bound service란 클라이언트-서버 인터페이스 안의 서버를 말하며 일종의 Service 클래스 구현으로, 이를 통해 다른 애플리케이션이 service에 바인딩하여 상호작용할 수 있도록 합니다. 이를 사용하면 component를 service에 바인딩하고, 요청을 보내고, 응답을 수신하며, 프로세스 간 통신(IPC)을 실행할 수 있습니다.

연결을 오래 유지하기위해 bindService()를 호출하여 애플리케이션 component를 service에 바인딩하는 겁니다. 일반적으로는 startService()를 호출하더라도 component가 service를 시작하도록 허용하지 않습니다. activity나 다른 component에서 service와 상호작용하기를 원하는 경우 bound service를 생성해야 합니다. 아니면 애플리케이션의 기능 몇 가지를 프로세스 간 통신(IPC)을 통해 다른 애플리케이션에 노출하고자 하는 경우에도 사용됩니다.

bound service를 생성하려면 클라이언트가 service와 통신할 수 있는 인터페이스를 정의해야 합니다. 바인딩을 제공하는 onBind() 콜백 메서드를 구현하여 인터페이스를 정의하는 IBinder를 반환하도록 해야 합니다. 그럼 클라이언트는 이 IBinder를 받아 해당 인터페이스를 통해 service와 상호작용 할 수 있습니다. 즉 다른 component가 bindService()를 호출하여 해당 인터페이스를 탐색하고, service에 있는 메서드를 호출할 수 있습니다. 일반적으로 bound service는 다른 애플리케이션 component에 사용될 때까지만 유지되고 백그라운드에서 무한히 실행되지는 않습니다. 그렇기 때문에 service에 바인딩된 component가 없으면 시스템이 이를 소멸시킵니다. 따로 중단하지 않아도 됩니다.

여러 클라이언트가 service에 한꺼번에 바인딩될 수 있습니다. 클라이언트가 service와의 상호작용이 끝나면 unbindService()를 호출하여 바인딩을 해제합니다. service에 바인딩된 클라이언트가 하나도 없으면 시스템이 해당 servcie를 소멸시킵니다.

Android 시스템이 service를 강제 중단하는 것은 메모리가 부족하여 사용자 포커스를 가진 activity를 위해 시스템 리소스를 회복해야만 하는 경우로만 국한됩니다. service가 사용자 포커스를 가진 activity에 바인딩 되었으면 종료될 가능성이 적고 service가 포그라운드에서 실행되도록 선언된 경우에는 종료될 가능성이 희박합니다.

bound service를 구현하는 데에는 여러 가지 방법이 있지만 started service보다 훨씬 복잡합니다. 다음 내용에 이를 확인 할 수 있습니다.

2) bound service 생성

바인딩을 제공하는 service를 생성하기 위해, 클라이언트가 service와 상호작용하는데 사용할 수 있는 프로그래밍 인터페이스를 제공하는 IBinder를 제공해야 합니다. 인터페이스를 정의하는 방법은 세 가지가 있습니다.

  • 바인더 클래스 확장

    • Service가 애플리케이션 전용이고 클라이언트와 같은 프로세스에서 실행되는 경우, 인터페이스를 생성할 때 Binder 클래스를 확장하고 그 인스턴스를 onBind()에서 반환하는 방식을 사용(가장 일반적인 경우).
    • 클라이언트는 Binder를 받고, 이를 사용하여 Binder 구현이나 Service에서 제공되는 public 메서드에 직접 액세스할 수 있음.
    • 단순히 백그라운드에서 작동하는 요소에 그치는 경우 선호되는 기법.
    • service를 다른 애플리케이션이나 별도의 프로세스에서 이용할 때는 사용 X.
  • 메신저 사용

    • 인터페이스가 여러 프로세스에서 작동해야 하는 경우, Messenger로 service 인터페이스를 생성할 수 있음.
    • service가 여러 가지 유형의 Message 객체에 응답하는 Handler를 정의.
    • Handler가 Messenger의 기초가 되어 클라이언트와 IBinder를 공유, 클라이언트는 Message 객체를 사용해 service에 명령어를 보냄.
    • 클라이언트가 자체적으로 Messenger를 정의하여 service가 메시지를 돌려보낼 수도 있음.
    • 프로세스 간 통신(IPC)을 실행하는 가장 간단한 방법. Messenger가 모든 요청을 단일 스레드로 큐에 저장하므로 service를 스레드로부터 안전하게 설계할 필요 X.
  • AIDL 사용

    • Android 인터페이스 정의 언어(AIDL)는 객체를 운영체제가 이해할 수 있는 원시 유형으로 해체한 다음, 여러 프로세스에서 마샬링하여 IPC를 실행.
    • Messenger를 사용하는 이전 기법은 AIDL을 기본 구조로 가짐.
    • Messenger는 한 번에 하나씩 요청을 수신하기에 service가 동시에 여러 요청을 처리하게 하려면 AIDL을 직접 사용해야 함. 이 경우에 service는 스레드로부터 안전해야 하고 다중 스레딩 처리가 가능해야 함.
    • AIDL을 직접 사용하려면 프로그래밍 인터페이스를 정의하는 .aidl 파일을 생성해야 함.
    • Android SDK 도구는 이 파일을 사용하여 인터페이스를 구현하고 IPC를 처리하는 추상 클래스를 생성. 그 후에는 개발자가 service 내에서 이 추상 클래스를 확장.
    • AIDL은 대부분의 애플리케이션에 적합하지 않음. 다중 스레딩 기능이 필요할 수 있어 구현이 더욱 복잡해지기 때문.

(ⅰ) 바인더 클래스 확장

service가 로컬 애플리케이션에서만 사용되고 여러 프로세스에서 작동할 필요가 없을 때 사용하며 가장 보편적인 경우입니다. 예를 들어 음악 앱의 경우 백그라운드에서 음악을 재생하는 자체 service에 activity를 바인딩합니다. 자체적인 Binder 클래스를 구현하여 클라이언트가 service 내의 public 메서드에 직접 액세스하도록 할 수도 있습니다. 설정하는 방법은 다음과 같습니다.

  1. service에서 다음 중 한 가지 기능을 하는 Binder의 인스턴스를 생성합니다.

    • 클라이언트가 호출할 수 있는 public 메서드를 포함.
    • 클라이언트가 호출할 수 있는 public 메서드가 있는 현재 Service 인스턴스를 반환.
    • 클라이언트가 호출할 수 있는 public 메서드가 포함된 service가 호스팅하는 다른 클래스의 인스턴스를 반환
  2. Binder의 인스턴스를 onBind() 콜백 메서드에서 반환합니다.

  3. 클라이언트에서 Binder를 onServiceConnected() 콜백 메서드에서 받아서 제공된 메서드로 bound service를 호출합니다.

service와 클라이언트가 같은 애플리케이션에 있어야 클라이언트가 반환된 객체를 전송하여 그 API를 적절하게 호출할 수 있습니다. 또한 service와 클라이언트는 같은 프로세스에 있어야 하기도 합니다. 이 방법에서는 여러 프로세스에서의 마샬링을 전혀 실행하지 않기 때문입니다.

다음 예시는 service가 Binder 구현을 통해 service 내의 메서드에 액세스할 수 있는 권한을 클라이언트에 제공하는 것을 보여줍니다.

public class LocalService extends Service {
    // 클라이언트에 제공된 바인더
    private final IBinder binder = new LocalBinder();
    // 랜덤 숫자 생성기
    private final Random mGenerator = new Random();

    /**
     *클라이언트 바인더에 사용되는 클래스입니다. 이 service는 항상  클라이언트와 
     * 동일한 프로세스에서 실행되므로 IPC를 처리할 필요가 없습니다.
      */
    public class LocalBinder extends Binder {
        LocalService getService() {
            // LocalService의 this 인스턴스를 리턴하기에 클라이언트는 public 메소드들을 호출할 수 있습니다.
            return LocalService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    /** 클라이언트를 위한 메소드 */
    public int getRandomNumber() {
      return mGenerator.nextInt(100);
    }
}

LocalBinder는 LocalService의 현재 인스턴스를 검색하기 위한 getService() 메서드를 클라이언트에 제공합니다. 이렇게 하면 클라이언트가 service 내의 public 메서드를 호출할 수 있습니다. 예를 들어 클라이언트는 service에서 getRandomNumber()를 호출할 수 있습니다.

다음은 버튼을 클릭했을 때 LocalService에 바인딩되어 getRandomNumber()를 호출하는 활동을 나타냅니다.

public class BindingActivity extends Activity {
    LocalService mService;
    boolean mBound = false;

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

    @Override
    protected void onStart() {
        super.onStart();
        // LocalService로 바인드
        Intent intent = new Intent(this, LocalService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unbindService(connection);
        mBound = false;
    }

    /** 버튼이 클릭되었을 때 호출(레이아웃 파일의 버튼에서 android:onClick 
       속성으로 이 메소드를 결합 **/
    public void onButtonClick(View v) {
        if (mBound) {
             // LocalService에서의 메소드를 호출. 그러나 이 호출이 중단될 경우,
            // 활동 성능 저하를 방지하기 위해 별도의 스레드에서 이 요청을
	       // 발생해야 합니다.
            int num = mService.getRandomNumber();
            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
        }
    }

    /** bindService()에 전달된 service 바인딩에 대한 콜백을 정의합니다. */
    private ServiceConnection connection = new ServiceConnection() {
	
	//onBind()가 반환한 IBinder를 전달
        @Override
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // LocalService로 바인드하여 IBinder를 캐스트하고 
	       //LocalService 인스턴스를 가져옵니다.
            LocalBinder binder = (LocalBinder) service;
            mService = binder.getService();
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };
}

위 예시는 클라이언트가 ServiceConnection 구현과 onServiceConnected() 콜백을 사용하여 service에 바인딩되는 방법을 보여줍니다. onStop() 메서드는 service에서 클라이언트의 바인딩을 해제합니다. 적절한 시기에 service에서 클라이언트의 바인딩을 해제해야 합니다

(ⅱ) 메신저 사용

service가 원격 프로세스와 통신해야 한다면 Messenger를 사용하여 service에 인터페이스를 제공할 수 있습니다. 이 방법을 사용하면 AIDL을 쓰지 않고도 프로세스 간 통신(IPC)을 실행할 수 있습니다.

인터페이스에 Messenger를 사용하는 것은 AIDL을 사용하는 것보다 더욱 간단합니다. Messenger는 모든 service 호출을 큐에 올리기 때문입니다. 순수한 AIDL 인터페이스는 service에 동시 요청을 보내고, 이를 받은 service는 다중 스레딩을 처리해야 합니다. 대부분의 애플리케이션에서는 service가 다중 스레딩을 처리할 필요가 없으므로 Messenger를 사용하여 한 번에 하나씩 호출을 처리할 수 있습니다. service의 다중 스레딩 처리가 중요한 경우, AIDL을 사용하여 인터페이스를 정의해야 합니다.

사용 방법은 다음과 같습니다.

  1. service가 각 클라이언트 호출의 콜백을 받는 Handler를 구현합니다.
  2. service가 Handler를 사용하여 Messenger 객체(Handler의 참조)를 생성합니다.
  3. Messenger가 IBinder를 생성하고, service가 이를 onBind()에서 클라이언트로 반환하도록 합니다.
  4. 클라이언트는 IBinder를 사용하여 Messenger(service의 Handler를 참조)를 인스턴스화하고, 이를 이용하여 Message 객체를 service에 전송합니다.
  5. service가 각 Message를 Handler로 수신합니다.handleMessage() 메서드를 사용합니다.

이렇게 하면 클라이언트가 service에서 호출할 메서드가 없습니다. 대신 클라이언트는 메시지(Message 객체)를 전달하여 service가 Handler로 받을 수 있도록 합니다.

다음은 Messenger 인터페이스를 사용하는 service의 간단한 예시입니다.

public class MessengerService extends Service {
    // service에 메시지를 표시하는  명령
    static final int MSG_SAY_HELLO = 1;

 //클라이언트에서 오는 메시지 Handler
    static class IncomingHandler extends Handler {
        private Context applicationContext;

        IncomingHandler(Context context) {
            applicationContext = context.getApplicationContext();
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Toast.makeText(applicationContext, "hello!", Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

   //  클라이언트가 IncomingHandler에 메시지를 보낼 수 있게 하는 대상
    Messenger mMessenger;

    /**
     * service에 바인딩할 때 service에 메시지를 보내기 위해 
     *  메신저에 인터페이스를 반환
     */
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
        mMessenger = new Messenger(new IncomingHandler(this));
        return mMessenger.getBinder();
    }
    
}

참고로 Handler의 handleMessage() 메서드에서 service가 수신되는 Message를 받고 what 멤버에 기초하여 무엇을 할지 결정합니다.

클라이언트는 service가 반환한 IBinder에 기초하여 Messenger를 생성하고 send()로 메시지를 전송하기만 하면 됩니다. 예를 들어, 다음은 service에 바인딩되어 MSG_SAY_HELLO 메시지를 service에 전달하는 간단한 활동입니다.

public class ActivityMessenger extends Activity {
    /**service와 통신하기 위한 메신저 */
    Messenger mService = null;

    /** service에서 바인드를 호출했는지 여부를 나타내는 flag */
    boolean bound;


     // service의 주요 인터페이스와 상호작용을 위한 클래스
    private ServiceConnection mConnection = new ServiceConnection() {
    
        public void onServiceConnected(ComponentName className, IBinder service) {
            // service와의 연결이 설정된 경우 이를 호출하여 service와
            // 상호 작용하는데 사용할 수 있는 개체를 제공.
            // 메신저를 사용하여 service와 통신하기 때문에
            // 여기서는 원시 IBinder 객체에서 클라이언트 측 표현을 얻음
            mService = new Messenger(service);
            bound = true;
        }

        public void onServiceDisconnected(ComponentName className) {
            // 서비스와의 연결이 예기치 않게 끊어졌을 때, 
	  	   // 즉 프로세스가 중단되었을 때 이를 호출
            mService = null;
            bound = false;
        }
    };

    public void sayHello(View v) {
        if (!bound) return;
        // 기본적으로 지원되는 'what' 값을 사용하여 service에 메시지 생성 및 전송
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
        try {
            mService.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

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

    @Override
    protected void onStart() {
        super.onStart();
        //service에 바인드
        bindService(new Intent(this, MessengerService.class), mConnection,
            Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // service 해제
        if (bound) {
            unbindService(mConnection);
            bound = false;
        }
    }
    
}

이 예시는 service가 클라이언트에 응답하는 방식을 보여주지는 않습니다. service가 응답하게 하려면 클라이언트에서 Messenger도 생성해야 합니다. 클라이언트가 onServiceConnected() 콜백을 받으면, send() 메서드의 replyTo 매개변수에 클라이언트의 Messenger를 포함하는 service에 Message를 전송합니다.

(ⅲ) AIDL 정보

AIDL는 자주 사용되는 내용도 아니고 복잡하기 때문에 자세한 내용은 생략합니다. 관심 있으신 분은 공식 문서를 확인해주시길 바랍니다.

https://developer.android.com/guide/components/aidl?hl=ko

3) service에 바인딩

service을 바인딩하려면 bindService()를 호출하면 됩니다. 그러면 Android 시스템이 service의 onBind() 메서드를 호출하고, 이 메서드가 service와의 상호작용을 위한 IBinder를 반환합니다.

바인딩은 비동기식으로 처리되고, IBinder를 클라이언트에 반환하지 않은 상태에서 bindService()가 즉시 반환됩니다. bindService()의 반환 값은 요청된 service가 존재하는지, 클라이언트에 service 액세스 권한이 있는지 나타냅니다.

IBinder를 수신하기 위해 클라이언트는 serivce와의 연결을 모니터링하는 ServiceConnection를 구현하여 인스턴스를 생성하고 이를 bindService()에 전달해야 합니다.

Android 시스템이 클라이언트와 service 사이에 연결을 생성하면 ServiceConnection에서 onServiceConnected()를 호출합니다. onServiceConnected() 메서드에는 IBinder 인수가 포함되고 클라이언트는 사용하여 bound service와 통신합니다.

Activity, service, content provider만 service에 바인딩할 수 있으며, broadcast receiver에서는 service에 바인딩할 수 없습니다.

클라이언트에서 service에 바인딩하는 방법은 다음과 같습니다.

  1. ServiceConnection을 구현합니다.이 구현으로 두 가지 콜백 메서드를 재정의해야 합니다.

    • onServiceConnected()
      시스템이 이를 호출하여 service의 onBind() 메서드가 반환한 IBinder를 전달합니다.
    • onServiceDisconnected()
      Android 시스템은 service로의 연결이 예기치 못하게 끊어졌을 경우, 예를 들어 service가 비정상 종료되었거나 중단되었을 때 호출합니다. 클라이언트가 바인딩을 해제할 때는 호출되지 않습니다.
  2. bindService()를 호출하여 ServiceConnection 구현을 전달합니다. 메서드가 false를 반환하면 클라이언트가 service에 제대로 연결되지 않았다는 것을 의미합니다. false이라도 클라이언트는 unbindService()를 호출해야 합니다. 그렇지 않으면 클라이언트가 유휴 상태인 service를 종료하지 못하게 합니다.

  3. 시스템이 onServiceConnected() 콜백 메서드를 호출하면, 인터페이스가 정의한 메서드를 사용하여 service에 호출을 시작할 수 있습니다.

  4. service로부터 연결을 해제하려면 unbindService()를 호출합니다. 클라이언트가 service에 여전히 바인딩 되었지만 앱이 클라이언트를 소멸시킬 때 이 소멸로 인해 클라이언트가 바인딩 해제됩니다. 클라이언트가 service와의 상호작용을 완료하는 즉시 바인딩을 해제하는 편이 좋습니다. 이렇게 하면 유휴 상태인 service를 종료할 수 있습니다.

다음 예시에서는 바인더 클래스를 확장해서 생성한 service에 클라이언트를 연결합니다. 여기에서는 반환된 IBinder를 LocalBinder 클래스로 전송하고 LocalService 인스턴스를 요청하기만 하면 됩니다.

LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
    // service와의 연결이 설정되면 호출
    public void onServiceConnected(ComponentName className, IBinder service) {
        //자체 프로세스에서 실행되는 명시적 service에 바인딩 되기 때문에
        // IIBinder를 특정 클래스로 캐스팅하여 직접 액세스할 수 있음
        LocalBinder binder = (LocalBinder) service;
        mService = binder.getService();
        mBound = true;
    }

    //service와의 연결이 예기치 않게 끊어지면 호출
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "onServiceDisconnected");
        mBound = false;
    }
};

다음 예시에서와 같이, ServiceConnection이 있으면 클라이언트는 이를 bindService()에 전달하여 service에 바인딩할 수 있습니다.

Intent intent = new Intent(this, LocalService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);

bindService()의 첫 번째 매개변수는 바인딩할 service의 이름을 명시적으로 지정하는 Intent입니다. 인텐트를 사용하여 Service에 바인딩하는 경우 명시적 인텐트를 사용하여 앱의 보안을 유지시켜야 합니다. 암시적 인텐트를 사용하여 service를 시작하면 어떤 service가 인텐트에 응답할지 확신할 수 없고 어떤 service가 시작하는지 사용자가 알 수 없으므로 보안 위험이 있습니다. Android 5.0(API 수준 21)부터는 암시적 인텐트로 bindService()를 호출하면 시스템에서 예외가 발생합니다.

두 번째 매개변수는 ServiceConnection 객체입니다.

세 번째 매개변수는 바인딩 옵션을 나타내는 플래그입니다. 일반적으로는 BIND_AUTO_CREATE가 되는데, 이는 service가 아직 활성화되지 않았을 경우 service를 생성하기 위함입니다. 그 외에는 BIND_DEBUG_UNBIND와 BIND_NOT_FOREGROUND를 사용할 수 있고 값이 없으면 0으로 설정합니다.

다음은 service로의 바인딩에 관한 몇 가지 중요한 참고사항입니다.

  • 항상 DeadObjectException 예외 사항을 작성해야함. 이 예외는 연결이 끊어지면 발생. 이 예외만 유일하게 원격 메서드에 의해 발생.
  • 객체는 여러 프로세스에 걸쳐 카운트되는 참조.
  • 일반적으로 클라이언트의 수명 주기가 발생하고 해제되는 타이밍에 맞추어 바인딩과 바인딩 해제를 짝지어야 함.
    • activity가 표시되는 동안에만 service와 상호작용해야 할 경우
      onStart()(바인딩)-> onStop()(바인딩 해제)
    • 백그라운드에서 activity가 중단되었을 때도 응답을 받게 하고 싶을 경우
      onCreate()(바인딩)-> onDestroy()(바인딩 해제)
  • 백그라운드에서 실행되는 시간을 포함하여 service가 실행되는 내내 activity가 service를 사용. service가 다른 프로세스에 있을 경우, 사용자가 그 프로세스의 가중치를 높이면 시스템이 이를 중단할 가능성이 커짐.
  • 일반적으로 activity의 onResume()onPause() 중에는 바인딩하거나 바인딩을 해제하지 말아야 함. 이러한 콜백은 모든 수명 주기 전환에서 발생하고 이런 전환에서 발생하는 처리는 최소한으로 유지해야 하기 때문.
  • 애플리케이션의 여러 activity가 동일한 service에 바인딩 되었고 두 activity 사이에 전환이 있을 경우, 현재 activity의 바인딩이 해제된 후(일시중지 중) 다음 activity가 바인딩되기 전(다시 시작 중)에 service가 제거되었다가 다시 생성될 수 있음.

4) started service에 바인딩

위에 언급되었듯이 시작되었으면서도 바인드된 service를 만들 수 있습니다. 다시 말해, startService()를 호출하여 service를 시작하고 이를 통해 service가 무한히 실행되면서 bindService()를 호출하여 클라이언트가 service에 바인딩되도록 할 수 있다는 의미입니다. service가 시작되고 바인드되도록 허용한다면, service가 실제로 시작되었을 때 시스템은 클라이언트가 모두 바인딩을 해제해도 서비스를 소멸시키지 않습니다. 그 대신 service를 직접 확실히 중단해야 합니다. 그러려면 stopSelf() 또는 stopService()를 호출하면 됩니다.

보통은 onBind() 또는 onStartCommand()를 구현하지만, 둘 다 구현해야 할 때도 있습니다. 예를 들어 음악 플레이어의 경우 service를 무한히 실행하면서 바인딩도 제공하는 것이 유용할 수 있습니다. 이 경우 어떤 activity에서 service를 시작해 음악을 재생하면, 사용자가 애플리케이션을 닫아도 음악이 계속 재생됩니다. 그런 다음, 사용자가 애플리케이션으로 다시 돌아오면 이 activity를 service에 바인딩하여 재생 제어권을 다시 획득할 수 있습니다.

여러 클라이언트를 하나의 service와 동시에 연결할 수 있습니다. 그러나 시스템이 IBinder service 통신 채널을 캐시합니다. 다시 말해, 첫 번째 클라이언트가 바인딩될 때만 시스템이 service의 onBind() 메서드를 호출해 IBinder를 생성합니다. 그러면 시스템이 동일한 service에 바인딩되는 모든 추가 클라이언트에 동일한 IBinder를 전달합니다. onBind()는 다시 호출하지 않습니다. 마지막 클라이언트가 service에서 바인딩을 해제하면 시스템은 service를 소멸시킵니다. 단, service가 startService()로 시작되었을 경우는 예외입니다. bound service 를 구현할 때 가장 중요한 부분은 onBind() 콜백 메서드가 반환하는 인터페이스를 정의하는 것입니다.

5) bound service 수명 주기 관리

모든 클라이언트에서 service가 바인딩 해제되면 Android 시스템이 이를 소멸시킵니다. 물론 startService() 호출과 함께 시작된 경우는 예외입니다. 따라서 service가 순수하게 bound service일 경우에는 service의 수명 주기를 관리하지 않아도 됩니다. 클라이언트에 바인딩되었는지 여부에 따라 Android 시스템이 대신 관리해주기 때문입니다. 그러나 onStartCommand() 콜백 메서드 구현을 선택하는 경우라면 service를 확실히 중지해야 합니다. service가 지금 시작된 것으로 간주되기 때문입니다. 이 경우 service가 클라이언트에 바인딩되어 있는지 여부와 관계없이, stopSelf()를 통해 service가 스스로 중지되거나 다른 component가 stopService()를 호출할 때까지 service가 실행됩니다.

또한 service가 시작되고 바인딩을 허용하는 경우 시스템에서 onUnbind() 메서드를 호출한 다음 클라이언트가 service에 바인딩 될 때, onRebind() 호출을 수신하고 싶다면 true를 선택적으로 반환할 수 있습니다. onRebind()는 void를 반환하지만 클라이언트는 여전히 onServiceConnected() 콜백에서 IBinder를 수신합니다. 위의 그림은 이런 종류의 수명 주기에 관한 로직을 보여줍니다.

출처 : https://developer.android.com/

이전 SERVICE 포스트
<service_1>
<service_2>
다음 SERVICE 포스트
<service 예제>

profile
안드로이드 개발자:D

0개의 댓글