IntentService란 무엇인가?
본격적인 예제에 앞서 안드로이드의 IntentService가 어떤 역할을 하는지 먼저 짚고 넘어가겠습니다. IntentService는 백그라운드 작업을 비동기적으로 처리하기 위한 서비스 클래스입니다. 액티비티에서 startService()를 호출하면 요청마다 새 인스턴스를 생성하지 않으며, 서비스 클래스 내에서 작업이 완료되면 자동으로 종료되거나 stopSelf()를 호출해 수동으로 종료할 수 있습니다.
이번 글에서는 IntentService에서 전달받은 데이터를 활용해 화면(UI)을 지속적으로 갱신하는 방법을 단계별로 살펴보겠습니다.
1단계: 프로젝트 생성
Android Studio에서 File → New Project를 선택하고, 필요한 정보를 모두 입력하여 새 프로젝트를 생성합니다.
2단계: 레이아웃 작성 (activity_main.xml)
res/layout/activity_main.xml 파일에 아래 코드를 추가합니다.
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android = "https://schemas.android.com/apk/res/android"
xmlns:app = "https://schemas.android.com/apk/res-auto"
xmlns:tools = "https://schemas.android.com/tools"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
tools:context = ".MainActivity">
<TextView
android:id = "@+id/text"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:text = "Start Service"
android:textSize = "25sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintLeft_toLeftOf = "parent"
app:layout_constraintRight_toRightOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
</android.support.constraint.ConstraintLayout>위 레이아웃에는 TextView 하나만 배치되어 있으며, IntentService로부터 데이터를 수신할 때마다 이 TextView의 텍스트가 갱신됩니다.
3단계: MainActivity 구현
src/MainActivity.java 파일에 아래 코드를 추가합니다.
package com.example.andy.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
TextView text;
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String someValue = intent.getStringExtra("someName");
text.setText(someValue);
}
};
@Override
protected void onStart() {
super.onStart();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.andy.myapplication");
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastReceiver, intentFilter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.text);
final Handler handler = new Handler();
TimerTask timertask = new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
public void run() {
startService(new Intent(MainActivity.this, service.class));
}
});
}
};
Timer timer = new Timer();
timer.schedule(timertask, 0, 10000);
}
@Override
protected void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
}
}여기서 핵심은 BroadcastReceiver입니다. onStart()에서 LocalBroadcastManager를 통해 리시버를 등록하고, onStop()에서 등록을 해제함으로써 메모리 누수를 방지합니다. 또한 Timer와 Handler를 조합해 10초(10,000ms)마다 서비스를 반복적으로 시작하도록 구성했습니다.
service.class 작성
이어서 service라는 이름의 클래스 파일을 만들고 다음 코드를 추가합니다.
package com.example.andy.myapplication;
import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
public class service extends IntentService {
public static volatile boolean shouldStop = false;
public service() {
super(service.class.getSimpleName());
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
protected void onHandleIntent(Intent intent) {
Intent intent1 = new Intent("com.example.andy.myapplication");
for(int i = 0; i < 10; i++) {
intent1.putExtra("someName", "Tutorialspoint.com "+i);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(shouldStop) {
stopSelf();
return;
}
}
}onHandleIntent() 메서드는 1초 간격으로 총 10번 브로드캐스트를 전송하며, 매번 "Tutorialspoint.com + 숫자" 형태의 값을 담아 보냅니다. MainActivity의 리시버가 이 값을 받아 TextView를 실시간으로 갱신하게 됩니다. volatile로 선언된 shouldStop 플래그를 확인해 필요 시 stopSelf()로 서비스를 종료할 수도 있습니다.
4단계: 매니페스트 설정 (manifest.xml)
마지막으로 AndroidManifest.xml에 아래 코드를 추가합니다.
<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "https://schemas.android.com/apk/res/android"
package = "com.example.andy.myapplication">
<uses-permission android:name = "android.permission.WAKE_LOCK"/>
<application
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 = ".MainActivity">
<intent-filter>
<action android:name = "android.intent.action.MAIN" />
<category android:name = "android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name = ".service"/>
</application>
</manifest><service android:name = ".service"/> 항목을 반드시 선언해야 서비스가 정상적으로 동작하며, WAKE_LOCK 권한은 기기가 절전 모드에 들어가더라도 백그라운드 작업이 계속 유지되도록 도와줍니다.
애플리케이션 실행 및 결과 확인
이제 앱을 실행해 보겠습니다. 실제 안드로이드 기기가 컴퓨터에 연결되어 있다고 가정합니다. Android Studio에서 프로젝트의 액티비티 파일 중 하나를 연 뒤 툴바의 실행(Run) 아이콘을 클릭하고, 목록에서 본인의 모바일 기기를 선택하세요. 그러면 기기 화면에 아래와 같은 결과가 표시됩니다.



위 실행 결과에서 확인할 수 있듯이, IntentService가 백그라운드에서 데이터를 지속적으로 전송하고 그 값이 화면 UI에 실시간으로 반영되는 것을 볼 수 있습니다. 이처럼 IntentService와 LocalBroadcastManager를 조합하면 백그라운드 작업 결과를 손쉽게 UI에 전달할 수 있습니다.