프로그래밍/안드로이드

안드로이드 - 데몬 백그라운드 서비스

가카리 2015. 12. 7. 21:53
반응형

 

서비스는 백그라운드에서 실행되며 사용자와 직접적인 상호작용을 하지 않는다.

 

전면에서 사용자를 대면하는 액티비티를 위해 연산이나 메소드 등의 서비스를 제공하는 것이 주된 임무이다.

 

클라이언트에서 어떤 식으로 호출하는 가에 따라 다음 두 가지 방법이 있다.

 

- 백그라운드 데몬 : 배경에서 계속 실행되는 프로세스이다. 클라이언트가 가동시켜 놓기만 하면 사용자의 명령이 없어도 지속적으로

실행된다.

- 원격 호출 인터페이스 : 클라이언트를 위해 특정한 기능을 제공하는 역할을 한다. 자신의 기능을 메소드로 노출시키며 클라이언트는 메소드를 호출함으로써

서비스를 이용한다.

 

사용 용도에 따라 가장 뚜렷한 차이가 발생하는 부분은 서비스의 생명 주기이다.

 

(출처 : http://ccdev.tistory.com/25)

 

백그라운드 서비스의 경우 onStartCommand() 가 호출되고 원격 호출일 때는 클라이언트에게 인터페이스를 노출하는 onBind 메소드가 호출된다.

 

원격 호출로 사용된다면 백그라운드 동작을 준비할 필요가 없으므로 onCreate에서는 최소하느이 초기화만 해 놓고 나머지 초기화는 onBind에서

 

처리한다. 설사 데몬으로 사용되도 onStartCommand에서 실행 준비를 해야하며 onCreate에서 미리 준비할 필요는 없다.

 

    int onStartCommand(Intent intent, int flags, int startId)

intent는 클라이언트가 서비스를 시작할 때 전달한 인텐트이다. 만약 프로세스가 강제 종료된 후 재시작되는 것이라면 이때는 null이 전달된다.

flags는 서비스의 요청에 대한 추가 정보이며 마지막 인수는 서비스 요청에 대한 고유한 식별자이다.

 

차우 stopSelfResult메소드로 서비스가 스스로 종료될 때 이 식별자를 사용한다.

리턴 값은 보통 접착식과 비접착식이 사용되는데 접착식은 시작과 종료가 명시적 비접착식은 명령을 처리하는 동안만 실행됨.

 

서비스는 메인 쓰레드에서 실행되므로 너무 오랜 시간을 끌면 안된다. 즉시 리턴해야되므로 오래 걸리는 작업은 반드시 쓰레드로 분리한다.

 

다음은 데몬으로 동작하는 서비스를 만드는 예제이다.

 

 

NewsService.java

package com.example.ch30_newsservice;

 

import android.app.Service;

import android.content.Intent;

import android.os.Handler;

import android.os.IBinder;

import android.os.Message;

import android.widget.Toast;

 

public class NewsService extends Service {

    boolean mQuit;

    

    @Override

    public void onCreate() {

        // TODO Auto-generated method stub

        super.onCreate();

        //뉴스를 읽기위한 네트워크 접속 초기화코드가 들어갈듯

    }

    

    @Override

    public void onDestroy() {

        // TODO Auto-generated method stub

        super.onDestroy();

        

        //서비스 종료를 알림

        //네트워트 종료 코드가 들어갈듯

        Toast.makeText(this, "Service end", 0).show();

        mQuit = true;

    }

    

    @Override

    public int onStartCommand(Intent intent, int flags, int startId) {

        // TODO Auto-generated method stub

     super.onStartCommand(intent, flags, startId);

      

     //본격적인 백그라운드 동작 시작

     mQuit = false;

     NewsThread thread = new NewsThread(this, mHandler);

     thread.start();//쓰레드 시작

     return START_STICKY;

    

    }

 

    

    //이번 예제는 원격호출을 지원하지않으므로 null 리턴시킴.

    @Override

    public IBinder onBind(Intent arg0) {

        // TODO Auto-generated method stub

        return null;

    }

    

    class NewsThread extends Thread{

        NewsService mParent;

        Handler mHandler;

        String[] arNews = {

                "크리스마스 다가옴",

                "설날 다가옴",

                "s전자 파업",

                "h자동차 파업",

                "가카리 취업 실패",

                "남북통일",

        };

        public NewsThread(NewsService parent, Handler handler){

            mParent = parent;

            mHandler = handler;

        }

        

        //쓰레드 부분

        public void run(){

            for(int idx = 0; mQuit == false;idx++){

                Message msg = new Message();//메시지를 만듬

                msg.what = 0;

                msg.obj = arNews[idx % arNews.length];//값을 넣어줌

                mHandler.sendMessage(msg);//메시지를 보냄

                try{

                    Thread.sleep(5000);//5초마다 메시지를 보냄

                }catch(Exception e){

                    ;

                }

            }

        }

    }

    

    Handler mHandler = new Handler(){//여기서 메시지를 받게 .

        public void handleMessage(android.os.Message msg) {

            if(msg.what == 0){

                String news = (String)msg.obj;

                Toast.makeText(NewsService.this, news, 0).show();//뉴스를 뿌림

            }

            

        };

    };

}

 

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.ch30_newsservice"

android:versionCode="1"

android:versionName="1.0" >

 

<uses-sdk

android:minSdkVersion="19"

android:targetSdkVersion="19" />

 

 

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<!-- enabled 서비스 사용여부 intent-filter부분에는 서비스의 이름을 지정함 -->

         <service android:name="com.example.ch30_newsservice.NewsService" android:enabled="true">

<intent-filter>

<action android:name="com.example.ch30.NEWS"/>

</intent-filter>

</service>

</application>

 

</manifest>

 

 

 

서비스는 백그라운드에서만 동작하며 스스로 기동하지 못하므로 클라이언트가 있어야만 테스트해 볼 수 있다.

클라이언트에서 서비스를 시작 및 중지할 때는 다음 메소드를 호출한다.

    ComponentName startService(Intent service)

    boolean stopService(Intent service)

startService 호출은 중첩되지 않으므로 몇 번을 시작했건 간에 stopService를 한 번만 호출해도 즉시 종료된다.

단 stopService를 호출했더라도 다른 응용 프로그램이 이 서비스를 사용하고 있다면 onDestroy는 호출되지 않는다.

 

방금 작성한 예제에서 다음을 추가하면 된다.

 

newscontroller.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    >

<Button

    android:id="@+id/newsstart"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:onClick="mOnClick"

    android:text="뉴스 서비스 시작"

    />

<Button

    android:id="@+id/newsend"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:onClick="mOnClick"

    android:text="뉴스 서비스 종료"

    />

</LinearLayout>

 

NewsController.java

 

package com.example.ch30_newsservice;

 

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.view.View;

 

public class NewsController extends Activity {

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.newscontroller);

    }

 

    public void mOnClick(View v){

        Intent intent;

        switch(v.getId()){

        case R.id.newsstart:

            intent = new Intent(this, NewsService.class);

            startService(intent);

            break;

        case R.id.newsend:

            intent = new Intent(this, NewsService.class);

            stopService(intent);

            break;

        }

    }

}

 

 

실행 화면

앱을 그냥 실행했을 때

뉴스 서비스 시작 버튼을 누르면 서비스가 시작됨.

반응형