자마린(Xamarin)

[추천 자마린 강좌]자마린.안드로이드에서 안드로이드 바운드 서비스 구현(Xamarin.Android Bound Service)

FSP 0 105 01.30 09:07

[추천 자마린 강좌]자마린.안드로이드에서 안드로이드 바운드 서비스 구현(Xamarin.Android Bound Service)

n 바인딩된 서비스는 Android Activity와 같은 클라이언트와 상호 작용할 수 있는 클라이언트-서버 인터페이스를 제공 하는 안드로이드 서비스 이다.

n 여러 클라이언트(액티비티등)가 동시에 서비스의 단일 인스턴스에 연결 되어 있을 수 있으며 바인딩된 서비스와 클라이언트는 서로 격리되며 대신 Android는 둘의 연결의 상태를 관리 하는 중간 개체를 제공한다.

클라이언트가 BindService 메서드를 사용하여 서비스에 바인딩 할 수 있는 세 가지 방법

ü 서비스 바인더(Service Binder) : 서비스 바인더는 Android.OS.IBinder 인터페이스를 구현하는 클래스로 대부분의 응용 프로그램은 인터페이스를 직접 구현하지 않고 대신 Android.OS.Binder 클래스를 상속받는다. 가장 일반적인 접근 방식이며 서비스와 클라이언트가 동일한 프로세스에 존재할 때 적합하다.

ü 메신저 사용(Using a Messanger) : 서비스가 별도의 프로세스에 있을 때 적합하다. 대신 서비스 요청은 Android.OS.Messenger를 통해 클라이언트와 서비스간에 정렬된다. Messenger 요청을 처리 할 Android.OS.Handler가 서비스에 생성된다.

ü Android 인터페이스 정의 언어 (AIDL, Using Android Interface Definition Language) 사용 : AIDL은이 가이드에서 다루지 않는 고급 기술이다.

n 클라이언트가 서비스에 바인딩되면 Android.OS.IBinder 객체를 통해 두 클라이언트 간의 통신이 이루어지는데 이 개체는 클라이언트가 서비스와 상호 작용할 수 있도록 하는 인터페이스를 담당한다. 각 Xamarin.Android 응용 프로그램이 처음부터 이 인터페이스를 구현할 필요는 없지만 Android SDK는 클라이언트와 서비스간에 객체를 마샬링하는 데 필요한 대부분의 코드를 처리하는 Android.OS.Binder 클래스를 제공한다.

n 클라이언트가 서비스를 끝내면 클라이언트에서 UnbindService 메서드를 호출하여 바인딩을 해제해야 한다. 마지막 클라이언트가 서비스에서 언 바운드되면 Android는 바인딩 된 서비스를 중지한다.

n 아래 그림은 Activity, ServiceConnection, Binder 및 Service가 서로 어떻게 관련되어 있는지 보여준다.

n 바인딩 된 서비스를 구현하기 위해 Service 클래스를 확장하며, 클라이언트(Activity)에서 IServiceConnection을 구현하고 Binder를 확장하여 클라이언트가 서비스와 통신 할 수 있도록 한다.

바운드 서비스를 사용하려면 다음 3가지 구성요소가 구현 되어야 한다.

Service 클래스 확장 및 생명주기 콜백 메소드 구현 : 서비스 요청 작업을 수행 할 코드가 포함된다.

IServiceConnection을 구현하는 클래스 : 이 인터페이스는 서비스에 대한 연결이 변경된 경우 (클라이언트가 서비스에 연결되거나 연결이 끊어진 경우) 클라이언트에게 알리기 위해 Android에서 호출하는 콜백 메서드를 제공한다. ServiceConnection은 클라이언트가 서비스와 직접 상호 작용하는 데 사용할 수있는 객체에 대한 참조를 제공하고 이 참조를 바인더(Binder)라고 한다.

IBinder 구현 클래스 : 바인더 구현은 클라이언트가 서비스와 통신하는 데 사용하는 API를 제공한다. 바인더는 바인딩 된 서비스에 대한 참조를 제공하거나 메서드를 직접 호출 할 수 있도록하거나 바인더가 응용 프로그램에서 바인딩 된 서비스를 캡슐화하고 숨기는 클라이언트 API를 제공 할 수 있다. IBinder는 원격 프로 시저 호출에 필요한 코드를 제공해야 하며 IBinder 인터페이스를 직접 구현할 필요는 없고 대신 IBinder에서 요구하는 대부분의 기본 기능을 제공하는 바인더 유형을 상속받아야 한다.

서비스 시작 및 바인딩 : 일단 서비스 연결, 바인더 및 서비스가 작성되면 Android 애플리케이션은 서비스 시작 및 바인딩을 담당한다.

n Service 클래스 확장

ü Xamarin.Android를 사용하여 서비스를 만들려면 Service를 서브 클래스 화하고 ServiceAttribute를 사용하여 클래스를 장식한다.

ü Xamarin.Android 빌드 도구는 속성을 사용하여 앱의 AndroidManifest.xml 파일에 서비스를 올바르게 등록한다. 액티비티와 마찬가지로 바인딩 된 서비스는 라이프 사이클의 중요한 이벤트와 관련된 자체 라이프 사이클 및 콜백 메소드를 가지고 있는데 아래는 서비스가 구현할 일반적인 콜백 메소드의 예이다.

ü OnCreate : Android가 서비스를 인스턴스화 할 때 호출되며 라이프 사이클 기간동안 서비스에 필요한 모든 변수 또는 객체를 초기화하는 데 사용되며 선택 사항이다.

ü OnBind : 모든 바인딩 된 서비스에서 구현해야 한다. 첫 번째 클라이언트가 서비스에 연결을 시도 할 때 호출되며 클라이언트가 서비스와 상호 작용할 수 있도록 IBinder 인스턴스를 반환한다. 서비스가 실행되는 동안 IBinder 개체는 향후 클라이언트에서 서비스 바인딩 요청을 수행하는 데 사용된다.

ü OnUnbind : 바인딩 된 모든 클라이언트가 언 바운드 될 때 호출된다. 이 메서드에서 true를 반환하면 새 클라이언트가 바인딩 할 때 OnUnbind에 전달된 인텐트가 나중에 OnRebind에서 호출된다. 언 바운드 후 서비스가 계속 실행될 때 이 작업을 수행합니다. 기본값은 false를 반환하며 아무 것도 수행하지 않는다. (선택 사항)

ü OnDestroy : Android가 서비스를 파괴 할 때 호출되며 자원 해제와 같이 필요한 정리 작업을 수행해야 하는데 선택 사항이다.

ü 아래는 바운드 서비스의 주요 수명주기 이벤트 이다.

// 서비스할 기능

public interface IHello

{

string hello(string name);

}

class Hello : IHello

{

public string hello(string name)

{

return $"안녕~ {name}";

}

}

// 안드로이드 서비스 클래스 : 서비스할 작업을 기술

[Service(Name = "example.xamarin.HelloService")]

public class HelloService : Service, IHello

{

static readonly string TAG = typeof(HelloService).FullName;

IHello h;

public IBinder Binder { get; private set; }

public override void OnCreate()

{

base.OnCreate();

Log.Debug(TAG, "OnCreate...");

h = new Hello(); //서비스할 메소드를 가진 클래스를 인스턴스화

}

//반드시 구현해야 되는 메소드

public override IBinder OnBind(Intent intent)

{

Log.Debug(TAG, " OnBind...");

this.Binder = new HelloBinder(this);

return this.Binder;

}

public override bool OnUnbind(Intent intent)

{

Log.Debug(TAG, " OnUnBind...");

return base.OnUnbind(intent);

}

public override void OnDestroy()

{

Log.Debug(TAG, " OnDestroy...");

Binder = null;

h = null;

base.OnDestroy();

}

// 서비스 메소드

public string hello(string name)

{

return h?.hello(name);

}

}

IBinder 구현하기

ü IBinder 객체는 클라이언트와 서비스 사이의 통신 채널을 제공한다. 안드로이드 응용 프로그램은 IBinder 인터페이스를 구현해서는 안되며, Android.OS.Binder를 확장해야 한다. Binder 클래스는 바인더 객체를 서비스 (별도의 프로세스에서 실행될 수 있음)에서 클라이언트로 마샬링하는 데 필요한 많은 인프라를 제공한다. 대부분의 경우 바인더 하위 클래스는 코드 몇 줄에 불과하며 서비스에 대한 참조를 래핑한다. 예문에서 TimestampBinder는 클라이언트에 TimestampService를 노출하는 속성을 가진다.

public class HelloBinder : Binder, IHello

{

public HelloService Service { get; private set; }

public HelloBinder(HelloService service)

{

this.Service = service;

}

public string hello(string name)

{

return Service?.hello(name); //바인더에서 서비스의 메소드를 호출

}

}

Service Connection 생성

ü IServiceConnection은 Binder 객체를 클라이언트(액티비티)에 연결한다. IServiceConnection 인터페이스를 구현하는 것 외에도 클래스는 Java.Lang.Object를 확장해야 한며 서비스 연결은 클라이언트가 바인더에 액세스 할 수있는 방법을 제공해야 하므로 바인딩 된 서비스와 통신해야 한다.

ü 바인딩 프로세스의 일부로 Android는 바인딩되는 서비스의 이름과 서비스 자체에 대한 참조를 보유하는 바인더를 제공하여 OnServiceConnected 메소드를 호출한다. 아래 예에서 서비스 연결에는 Binder에 대한 참조를 보유하는 속성과 클라이언트가 서비스에 연결되어 있는지 여부에 대한 부울 플래그라는 두 가지 속성이 있다.

ü OnServiceDisconnected 메서드는 클라이언트와 서비스 간의 연결이 예기치 않게 손실되거나 손상된 경우에만 호출되며 이 방법을 사용하면 클라이언트가 서비스 중단에 응답 할 수 있다.

[HelloServiceConnection.cs]

using Android.Util;

using Android.OS;

using Android.Content;

namespace BoundServiceDemo

{

// 서비스에 대한 연결이 변경된 경우(클라이언트가 서비스에 연결되거나 연결이 끊어진 경우)

// 클라이언트에게 알리기 위해 Android에서 호출하는 콜백 메서드를 제공한다.

// ServiceConnection은 클라이언트가 서비스와 직접 상호 작용하는 데 사용할 수있는

// 객체에 대한 참조를 제공하고 이 참조를 바인더(Binder)라고 한다.

public class HelloServiceConnection : Java.Lang.Object, IServiceConnection, IHello

{

static readonly string TAG = typeof(HelloServiceConnection).FullName;

MainActivity activity;

public bool IsConnected { get; private set; }

public HelloBinder Binder { get; private set; }

public HelloServiceConnection(MainActivity activity)

{

IsConnected = false;

Binder = null;

this.activity = activity;

}

public void OnServiceConnected(ComponentName name, IBinder service)

{

Binder = service as HelloBinder;

IsConnected = this.Binder != null;

string message = "OnServiceConnected :: ";

Log.Debug(TAG, $"OnServiceConnected {name.ClassName}");

if(IsConnected)

{

message = message + " bound to service " + name.ClassName;

this.activity.UpdateUiForBoundService();

}

else

{

message = message + " not bound to service " + name.ClassName;

this.activity.UpdateUiForUnboundService();

}

Log.Info(TAG, message);

activity.messageTextView.Text = message;

}

public void OnServiceDisconnected(ComponentName name)

{

Log.Debug(TAG, $"OnServiceDisConnected {name.ClassName}");

IsConnected = false;

Binder = null;

activity.UpdateUiForUnboundService();

}

public string hello(string name)

{

if (!IsConnected) return null;

return Binder?.hello(name);

}

}

}

MainActivity안의 GetHello 번튼 클릭시 serviceConnection의 바인더를 사용하여 Service의 메서드를 호출 할 수 있다.

//GetHello 버튼 클릭

void btnGetHello_Click(object sender, EventArgs e)

{

if (serviceConnection.IsConnected)

messageTextView.Text = serviceConnection.Binder.Service.hello(nameEditText.Text);

else

messageTextView.SetText(Resource.String.service_not_connected);

}

명시적 인텐트(Explicit Intent)가 있는 서비스 시작 및 바인딩

n 바운드 서비스를 사용하려면 클라이언트 (예 : Activity)가 Android.Content.IServiceConnection을 구현하고 BindService 메서드를 호출하는 객체를 인스턴스화 해야한다. BindService는 서비스가 바인딩 된 경우 true를 반환하고 그렇지 않으면 false를 반환하며 BindService 메서드는 세 가지 매개 변수를 사용한다.

ü Intent - Intent는 연결할 서비스를 명시.

ü IServiceConnection 개체 : 바인딩 된 서비스가 시작되고 중지 될 때 클라이언트에 알리는 콜백 메서드를 제공하는 중개자.

ü Android.Content.Bind enum : 객체를 바인딩 할 때 시스템에서 사용하는 플래그 집합으로 가장 일반적으로 사용되는 값은 Bind.AutoCreate이며, 서비스가 아직 실행되지 않은 경우 자동으로 시작된다.

n 명시적 인텐트를 사용하여 Actiivity에서 바운드 서비스를 시작하는 방법

protected override void OnStart()

{

base.OnStart();

if (serviceConnection == null) serviceConnection = new HelloServiceConnection(this);

Intent intent = new Intent(this, typeof(HelloService));

BindService(intent, serviceConnection, Bind.AutoCreate);

}

#안드로이드서비스, #자마린서비스, #바운드서비스, #자마린바운드서비스, #자마린강좌, #자마린강의, #자마린교육, #자마린출강, #자마린, #Xamarin, #자마린안드로이드, #Xamarin.Android, #자마린폼즈 

, , , , , , , , , , , ,

Comments