AIDL과 Bind Service 사용하기

James_·2022년 9월 6일
0

서비스와 뷰(액티비티,프래그먼트)와 통신하기 위해서 여러가지 방법이 있지만 AIDL을 사용해보았다.

AIDL

클라이언트와 서비스가 모두 동의한 프로그래밍 인터페이스를 정의하여 프로세스 간 통신(IPC)으로 서로 통신할 수 있다.

먼저 AIDL파일을 만들어준다.
File -> New -> AIDL File
우선 콜백과 서비스를 만들어주었다.

AIDL 파일 만들기

// IStepService.aidl
package com.example.plogging;

import com.example.plogging.IStepServiceCallback;

interface IStepService {

    boolean addCallback(IStepServiceCallback callback);
    boolean removeCallback(IStepServiceCallback callback);
    void startTimer();
    void stopTimer();

}
// IStepServiceCallback.aidl
package com.example.plogging;

// Declare any non-default types here with import statements

interface IStepServiceCallback {
   void onStepChanged(int stepCount);
   void onMiniutesChanged(int minutes);
}

AIDL파일은 자바 기반으로 되어있어서 자바 기반으로 작성해준다.
파일을 만들고 빌드를 해줘야 import할 수 있기 때문에 빌드를 해줘야 한다.
Build -> Make Build

서비스 코드 추가하기

class SomeService : Service(){

    val listeners = arrayListOf<IStepServiceCallback>()
    private val binder = object : IStepService.Stub(){
        override fun addCallback(callback: IStepServiceCallback?): Boolean {
            callback?.let {
                listeners.add(it)
            }
            return true
        }

        override fun removeCallback(callback: IStepServiceCallback?): Boolean {
            callback?.let {
                listeners.remove(it)
            }
            return true
        }

        override fun startTimer() {
            this@SomeService.startTimer()
        }

        override fun stopTimer() {
            this@SomeService.stopTimer()
        }
  
  
    // 데이터가 변경되는 시점에 리스너들에게 데이터가 변경되었다는 것을 알려준다.
  	private fun dataChanged(step:Int){
    	listeners.forEach {
            it.onStepChanged(currentStep)
        }
    }

}

여러개의 뷰들이 서비스에서 데이터를 받을 수 있으므로 listeners callback리스트들로 선언해주었다.

그리고 서비스의 override method인 onBind에 biner로 리턴해준다.

override fun onBind(p0: Intent?): IBinder {
        return binder
    }

액티비티/프래그먼트에 바인드 추가하기

class HomeFragment:Fragment(){
	private var bounded = false
    private var iStepService: IStepService? = null
    private lateinit var stepCallback: IStepServiceCallback
    private var bounded = false
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
 
        stepCallback = object : IStepServiceCallback.Stub() {

            override fun onStepChanged(stepCount: Int) {
                viewModel.currentStep.postValue(stepCount)
                bounded = true
            }

            override fun onMiniutesChanged(minutes: Int) {
                viewModel.currentMinutes.postValue(minutes)
                bounded = false
            }
        }
    }
    
        private val connection = object : ServiceConnection {
        override fun onServiceConnected(p0: ComponentName?, service: IBinder?) {
            Log.d("TAG", "onServiceConnected: attatched")
            iStepService = IStepService.Stub.asInterface(service)
            iStepService!!.addCallback(stepCallback)
            iStepService!!.startTimer()
        }

        override fun onServiceDisconnected(p0: ComponentName?) {
            Log.d("TAG", "onServiceDisconnected: disconneced")
            iStepService = null
        }

    }
}

callback을 초기화해주고 바인드서비스를 만들기 위한 ServiceConnection을 선언해주었다.
그리고 onStart,onStop에 register/unregister해준다

    override fun onStart() {
        super.onStart()

        if(bounded){
            val intent = Intent(requireContext(),StepCounterService::class.java)
            requireActivity().bindService(intent,connection, Context.BIND_AUTO_CREATE)
        }
    }
    
   	override fun onStop() {
        super.onStop()
        if(bounded){
            iStepService?.removeCallback(stepCallback)
            requireActivity().unbindService(connection)
        }

    }
profile
Android 개발자

0개의 댓글