안드로이드 개발 서비스 바인딩 (Service Bind) 예제 구현하는 방법

 

환경: Android Studio

 

안드로이드에는 크게 4개의 컴포넌트로 나눕니다. 그 중 하나가 서비스(Service) 입니다. 서비스는 안드로이드 OS 에서 백그라운드로 돌아가는 객체 입니다. 실행과 종료는 Activity 에서 하겠죠. 주로 주기적인 관찰과 피드백이 필요한 기능에 사용합니다. 이런 Service 에는 두 종류가 있습니다. 연결을 유지해서 데이터를 주고 받을 수 있는  Bound Service 와 시작과 종료에만 관여하는 UnBound Service 입니다. Service 컴퍼넌트와 데이터를 주고 받으며 관리하고 싶다면 Bound Service 로 만들어야겠죠.

 

그림처럼 Bound/UnBound 는 시작 함수부터 틀립니다. 그리고 연결을 유지하고 데이터를 전송 받기 위한 ServiceConnection() 객체와 IBinder 인터페이스 객체가 필요합니다. ServiceConnection() Service를 호출하는 Activity 에 만들어야 하고, IBinder Service 에서 생성한 후 리턴해야 합니다. Bound Service 는 여러 클라이언트에서 동시에 접속이 가능하며, 연결이 전부 끊기면 자동으로 소멸합니다.

안드로이드 개발 서비스 바인딩 (Service Bind) 예제 구현하는 방법

 

먼저 Service 를 만들어 보겠습니다. 이전 unbind 서비스 클래스와 달라진 것이 있다면 Binder 클래스와 데이터를 리턴하는 getBroastData() 함수 입니다. Binder Activity 와 연결을 위한 클래스 이며, getBroastData() 는 데이터를 전달하기 위한 임의로 만든 함수 입니다. 그리고 위의 생명주기 그림에서 보았듯이 시작은 onBind() 함수에서 시작합니다. 반드시 IBinder 인터페이스 클래스를 넘겨야 합니다.

public class PhoneCallService extends Service {

    IBinder mBinder = new PhoneCallBinder();

    class PhoneCallBinder extends Binder {
        PhoneCallService getService() { // 서비스 객체를 리턴
            return PhoneCallService.this;
        }
    }

    public String getBroastData(){
        return "PhoneCallService data";
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "서비스 onBind 에서 시작");
        return mBinder;
    }

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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "서비스 시작");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "서비스 종료");
        super.onDestroy();
    }
}

 

Activity 에는 서비스 실행과 종료, 데이터를 가져오기 위한 버튼 3개를 만들었습니다. 서비스를 실행하는 bindService(), 종료할 때 unbindService() 함수를 호출합니다. 마지막 3번째 버튼에서는 Service 에 만들어 놓은 getBroastData() 함수를 호출해서 String 데이터를 가져와 화면에 표시합니다. Bound Service 함수를 호출할 때 ServiceConnection 객체를 넘겨야 합니다. UnBound Service 에서는 없던 클래스 입니다.  

public class PhoneCallActivity extends AppCompatActivity {

    PhoneCallService ms; // 서비스
    boolean isService = false; // 서비스 실행 확인
    TextView mTvCallData;

    ServiceConnection conn = new ServiceConnection() {
        public void onServiceConnected(ComponentName name,
                                       IBinder service) {
            // 서비스와 연결되었을 때 호출되는 메서드
            PhoneCallService.PhoneCallBinder mb =
                    (PhoneCallService.PhoneCallBinder) service;
            ms = mb.getService();
            isService = true; // 실행 여부를 판단
        }
        public void onServiceDisconnected(ComponentName name) {
            // 서비스와 연결이 끊기거나 종료되었을 때
            isService = false;
        }
    };

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

        Button btnStart = (Button) findViewById(R.id.btn_service_start);
        Button btnEnd = (Button) findViewById(R.id.btn_service_end);
        Button btnCallData = (Button) findViewById(R.id.btn_service_data);
        mTvCallData = (TextView) findViewById(R.id.tv_service_data);

        btnStart.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // 서비스 시작하기
                Intent intent = new Intent(
                        getApplicationContext(),// Activiey Context
                        PhoneCallService.class); // 이동할 서비스 객체
                bindService(intent, conn, Context.BIND_AUTO_CREATE);
            }
        });

        btnEnd.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                // 서비스 종료하기
                unbindService(conn);
            }
        });

        btnCallData.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (!isService) {
                    Toast.makeText(getApplicationContext(),
                            "서비스가 실행 중이 아닙니다. ",
                            Toast.LENGTH_LONG).show();
                    return;
                }
                String data= ms.getBroastData();//서비스에서 가져온 데이터
                mTvCallData.setText(data);
            }
        });
    }
}

 

activity_phone_call.xml : 화면을 구성하는 XML 은 다음과 같습니다

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/btn_service_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="서비스 시작" />

    <Button
        android:id="@+id/btn_service_end"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="서비스 종료" />

    <Button
        android:id="@+id/btn_service_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="데이터 가져오기" />

    <TextView
        android:id="@+id/tv_service_data"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="5dp"
        android:gravity="center"
        android:background="#d2bebe"
        android:textColor="#FFFFFF"/>
</LinearLayout>

 

다음은 AndroidManifest.xml Service 를 등록해야 합니다. 위치는 <application> 태그 안입니다

<application
    android:name=".CustomApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".PhoneCallActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".PhoneCallService" />
</application>

 

Activity 를 실행해서 서비스 시작과 종료 버튼을 클릭해 보세요. 서비스 내부에 추가한 콘솔 출력 함수인 Log.d() 를 통해서 이상 없이 수행되고 있음을 알 수 있습니다. 그리고 서비스를 실행한 상태에서 데이터 가져오기버튼을 클릭하면 바로 아래의 TextView 위젯에 Service 에서 가져온 데이터를 표시합니다.

안드로이드 개발 서비스 바인딩 (Service Bind) 예제 구현하는 방법

 

Posted by 녹두장군