티스토리 뷰

Android

7 . 서비스 : Service

알 수 없는 사용자 2018. 10. 3. 20:01



저번 포스팅에서 다루었던

안드로이드 애플리케이션의 4가지 구성 요소 중

이번에는 서비스에 대해 다루어 보겠습니다.

간단한 예제를 만들 때는 많이 사용되지 않겠지만

실제로 애플리케이션을 만들 거나 우리가 사용하고 있는

애플리케이션에도 많이 사용되고 있기 때문에

중요한 내용일 거로 생각합니다.


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


Service : 서비스



1. 구체적으로 어떤 기능을 서비스라 할까?


 저번 포스팅에서 서비스는 "백그라운드에서 오랫동안 실행되는 작업이나 원격 프로세스를 위한 컴포넌트입니다." 라고 간단히 소개했습니다.

솔직히 말해서 글로 백번 보는 것보다 실생활 예로 보는 것이 이해도 빠르고 딱 와닿을 것입니다. 

지금은 스마트폰을 가지고 있는 사람이라면 누구나 쓰는 카카오톡이 대표적인 예입니다. 

우리가 카카오톡을 실행하지 않고 있어도 상대방에게서 메시지가 오면 알림이 옵니다. 이 기능이 바로 서비스 기능입니다.

사용자가 사용하고 있지 않아도 스마트폰 백그라운드, 쉽게 말해 사용자에게 보이진 않지만 작동되고 있는 것입니다.

이뿐만이 아닙니다. 멜론, 지니와 같은 음악 플레이어도 음악을 재생한 다음 화면을 꺼도 음악이 멈추지 않습니다.

이것 또한 액티비티와 상관없이 스마트폰 백그라운드에서 작동되고 있기 때문에 음악이 재생되는 것입니다.




2. 서비스의 종류와 생명주기


 


[출처] https://kairo96.gitbooks.io/android/content/ch2.5.1.html


서비스를 구현할 방법은 두 가지로 분류할 수 있습니다.


① StartService (시작 타입 서비스)

startService() 메소드를 호출하여 서비스를 시작하는 방법입니다. 

일반적으로 작업이 완료되면 서비스를 종료하는 반면에 한 번 시작되면 백그라운드에서 무한정 실행합니다. 그 때문에 서비스가 한번 실행되고 종료되지 않았다면 다시 서비스를 여러 번 호출하더라도 서비스 상태에는 변화가 없게 됩니다. 따라서 StartService는 서비스를 시작하는 목적보다는 인텐트를 서비스 쪽으로 전달하는 목적으로 더 많이 사용됩니다.

그리고 하나의 프로세스 안에서 동작하며, 패키지 내 컴포넌트들과 유기적으로 통신하는 역할을 합니다. 

Bound Service와 비교하여 Unbound Service, 시작타입의 서비스라고도 합니다.


② BoundService (연결 타입 서비스)

  bindService() 메소드를 호출하여 서비스를 시작하는 방법입니다. 마치 클라이언트-서버와 같이 동작하는데 이때 서비스가 서버 역할을 담당합니다.

액티비티는 서비스에 어떠한 요청을 할 수 있고, 서비스로부터 결과를 받을 수 있습니다. StartService는 서비스로부터 반환결과를 받을 수 없습니다.

또한 프로세스 간 통신에도 사용되고 하나의 서비스에 다수의 액티비티 연결이 가능합니다.

하지만 연결된 액티비티가 사라지면 서비스도 소멸하여 백그라운드에서 무한히 실행되지가않습니다.


서비스의 종류마다 각자의 장단점을 가지고 있습니다. 때문에 두 가지 방법을 동시에 작동하게 구현할 수도 있습니다. 몇 개의 콜백메소드를 동시에 구현하여

시작 타입을 위해서 필요한 onStartCommand()메소드와 연결 타입을 위해서 필요한 onBind() 메소드를 구현하면 됩니다.







3. StartService 테스트

 


서비스 타입 중 StartService 타입을 테스트 해보겠습니다. 위에서도 말했다시피 StartService는 서비스로 인텐트를 전달 목적으로 많이 사용되기 때문에 

서비스로 데이터를 전달하고 다시 서비스에서 데이터를 전달받았을 때 toast 메시지를 통해 결과를 출력해보도록 하겠습니다.



① 서비스로 보내기 위한 text를 입력할 EditText 한 개와 서비스를 실행할 버튼 한 개를 추가합니다.






② 서비스에서 작동할 class는 액티비티와 다르게 생성해야 합니다.


 app - New - Service에서 Service를 클릭하시고 이름을 설정하여 만들면 서비스에서 작동할 클래스가 생성됩니다.

또한 이렇게 생성된 Service 클래스는 액티비티와 비슷하게 AndroidManifest.xml에서 서비스 태그가 생성된 것을 확인할 수 있습니다.


<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>





③ onCreate(), onDestroy(), onStartCommand() 메소드를 오버라이드 해줍니다. 

 

@Override
public void onCreate() {
Log.d(TAG,"onCreate() 호출");
super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
Log.d(TAG,"onDestroy() 호출");
super.onDestroy();
}


onCreate() 와 onDestroy() 메소드는 서비스의 수명주기이며, onStartCommand는 인텐트 객체를 전달받기 위한 콜백메소드입니다.

이때  onStartCommand() 메소드 "@IntDef(value = {Service.START_FLAG_REDELIVERY, Service.START_FLAG_RETRY..." 이 부분에 오류가 나타나는데 이부분은 삭제해주셔도 무방합니다.

각 서비스의 수명주기에 해당하는 메소드에는 각각 호출되는 때를 알아보기 위해 Log를 찍어보도록 합니다.


④ 메인액티비티에서 서비스로 데이터를 전달합니다.


EditText editText;

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

editText = (EditText)findViewById(R.id.editText);

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name = editText.getText().toString();
Intent intent = new Intent(getApplicationContext(), MyService.class);
intent.putExtra("command","show");
intent.putExtra("name", name);
startService(intent);
}
});
}


이전에 포스팅한 Intent를 사용하여 command 키값을 가진 show데이터와 name 키값을 가진 name 데이터를 intent에 포함해줍니다.

물론 name값을 EditText에 작성한 글이 저장됩니다. 

startService() 에서는 서비스를 실행시킴과 동시에 intent를 같이 넘겨 서비스가 intent를 전달받을 수 있게 됩니다.




⑤ 메인액티비티에서 전달한 intent를 서비스에서 받고 다시 intent 전달합니다.

 

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand() 호출");
if(intent == null){
return Service.START_STICKY;
}else {
String command = intent.getStringExtra("command");
String name = intent.getStringExtra("name");
Toast.makeText(getApplicationContext(), "command : " + command+", "+"name :" + name, Toast.LENGTH_LONG).show();

try{
Thread.sleep(5000);
}catch(Exception e){}

Intent intent2 = new Intent(getApplicationContext(), MainActivity.class);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent2.putExtra("command","show");
intent2.putExtra("name", name + "from Service");
startActivity(intent2);

}

return super.onStartCommand(intent, flags, startId);
}


서비스를 호출했을 때 인텐트 객체를 받는 메소드는 onStartCommand()입니다. 


intent가 null일 경우와 아닐 경우를 처리한 이유는 시스템 재시작에 있습니다.


시스템에 의해 서비스가 자동으로 다시 시작될 수 있기 때문에 intent 객체 또한 null값 일수 있습니다. 그러므로 intent객체가 null인지 먼저 체크한 후 null 값일 경우

Service.START_STICKY를 리턴하게 됩니다. 이 값을 반환하면 서비스가 비정상 종료되어도 시스템이 자동으로 재시작될 수 있습니다.


그리고 정상적으로 intent 객체를 전달받았을 때 intent 객체의 저장된 값을 toast 메시지로 출력할 수 있습니다.

또한 전달받은 데이터와 새로운 데이터를 다시 intent에 포함하여 다시 메인 액티비티를 호출할 수 있습니다.


메인 액티비티로 전달할 intent에 FLAG_ACTIVITY_NEW_TASK를 꼭 설정해 주어야 합니다. 서비스는 화면에 표시되지 않고 백그라운드에서 실행되기 때문에 서비스에서 화면이 있는 액티비티를 호출할 경우 새로운 테스크를 생성해야 하기 때문입니다. 

또한 FLAG_ACTIVITY_SINGLE_TOP과 FLAG_ACTIVITY_CLEAR_TOP은 호출하고자 하는 액티비티가 이미 만들어져 있으면 재사용하도록 사용해주는 것이 좋습니다.




⑥ 마지막으로 서비스에서 전달한 intent를 메인에서 받아 출력합니다.


@Override
protected void onNewIntent(Intent intent) {
if(intent != null){
String command = intent.getStringExtra("command");
String name = intent.getStringExtra("name");
Toast.makeText(getApplicationContext(), "command : " + command+", "+"name : "+ name ,Toast.LENGTH_LONG).show();
}

super.onNewIntent(intent);
}


서비스에서  intent의 플래그를 FLAG_ACTIVITY_SINGLE_TOP과 FLAG_ACTIVITY_CLEAR_TOP으로 설정한 것과 같이 메인 액티비티는 서비스를 호출하면서 이미 메모리에 생성되어 있기 때문에 onNewIntent() 메소드가 호출됩니다.


만약 메모리에 존재하지 않고 새로 호출되는 액티비티라면 onCreate() 메소드가 호출되겠지만 이미 존재하는 액티비티가 호출되는 경우에는 onNewIntent() 메소드가 호출됩니다.

때문에 onNewIntent() 메소드에서 전달받은 intent에 저장된 값을 통해 toast 메시지를 출력할 수 있습니다.



'Android' 카테고리의 다른 글

9. 위험 권한 : Dangerous Permission  (0) 2018.10.07
8. 브로드캐스트 수신자 : Broadcast Receiver  (0) 2018.10.06
6. 안드로이드의 4가지 구성 요소 & Intent  (0) 2018.09.30
5. Page Sliding  (0) 2018.09.30
4. Tween Animation  (0) 2018.09.29
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함