2011年7月15日金曜日

別スレッドで動くIntentService(後始末が自動的)

Androidにはサービスという、Linux等でいうデーモンのような仕組みがある。
何もしないシンプルなサービスでは、Serviceクラスを継承した。
今回は、IntentServiceクラスを継承する。

2つの違いは、以下の通り。
・IntentServiceのonHandleIntentメソッドが、別スレッドで実行される(非同期)
非同期の関連キーワード:AsyncTask、Thread、Runnable
・IntentServiceは、処理が終わると、自動的にonDestroyメソッドが呼ばれサービスが停止すること。

■別スレッドで動くIntentServiceを作る
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:IntentServiceTest0
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.intentservicetest0
「アクティビティ名」:IntentServiceTest0Activity

2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyIntentService』クラスを作成
ソース内容は以下の通り。

基本的には、MyIntentServiceクラスをIntentServiceクラスの継承クラスとする。
Seriviceの継承とは異なり、コンストラクターのみ強制オーバーライドであった。

Eclipseのコードアシスタントでは、第一引数ありのコンストラクタを生成してくれる、
しかし、
Activityで以下のコードでサービスを起動するには、
引数なしのコンストラクタが必要となることに注意。
startService(new Intent(getBaseContext(), MyIntentService.class));

onBind、onCreate、onDestroy、onStartは、オーバーライドは任意。
今回はログ確認用に、オーバーライドしている。

また、別スレッドで動くonHandleIntentメソッドには、スリープを5秒間入れた。
これは、onHandleIntentがどのスレッドで動くか調べるためだ。
結果、onHandleIntentは、新規スレッドで動作した。

つまりは、以下のコードにおけるIntentServiceは、
Activityと同プロセスだが、別スレッドで動作している。

package jp.co.example.intentservicetest0;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class MyIntentService extends IntentService{

 private final String TAG = this.getClass().getSimpleName();

 public MyIntentService(String name) {
  super(name);
  // TODO 自動生成されたコンストラクター・スタブ
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
 }

 public MyIntentService() {
  super("MyIntentService");
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
 }

 @Override
 protected void onHandleIntent(Intent arg0) {
  // TODO 自動生成されたメソッド・スタブ
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
  try {
   Thread.sleep(5000);
  } catch (InterruptedException e) {
   // TODO 自動生成された catch ブロック
   e.printStackTrace();
  }
 }

 @Override
 public IBinder onBind(Intent intent) {
  // TODO 自動生成されたメソッド・スタブ
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
  return super.onBind(intent);
 }

 @Override
 public void onCreate() {
  // TODO 自動生成されたメソッド・スタブ
  super.onCreate();
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
 }

 @Override
 public void onDestroy() {
  // TODO 自動生成されたメソッド・スタブ
  super.onDestroy();
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
 }

 @Override
 public void onStart(Intent intent, int startId) {
  // TODO 自動生成されたメソッド・スタブ
  super.onStart(intent, startId);
  Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName());
 }

}

3)画面にスタートボタン、ストップボタンを作る
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <Button android:text="Start" android:id="@+id/start_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
    <Button android:text="Stop" android:id="@+id/stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>

</LinearLayout>


4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下で次を実行。
startService(new Intent(getBaseContext(), MyIntentService.class));
ストップボタン押下で次を実行。
stopService(new Intent(getBaseContext(), MyIntentService.class));

全体のコードは以下の通り。
package jp.co.example.intentservicetest0;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class IntentServiceTest0Activity extends Activity {
 Button startButton;
 Button stopButton;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViews();

        startButton.setOnClickListener(new OnClickListener() {

   public void onClick(View v) {
    // TODO 自動生成されたメソッド・スタブ
    startService(new Intent(getBaseContext(), MyIntentService.class));
   }
  });

        stopButton.setOnClickListener(new OnClickListener() {

     public void onClick(View v) {
      // TODO 自動生成されたメソッド・スタブ
      stopService(new Intent(getBaseContext(), MyIntentService.class));
     }
    });
    }

    protected void findViews() {
     startButton = (Button)findViewById(R.id.start_button);
     stopButton = (Button)findViewById(R.id.stop_button);
    }
}

5)マニフェストでサービス許可する
AndroidManifest.xmlにタグにサービスクラス名を指定して、以下のようにサービスを許可する。


<application android:icon="@drawable/icon" android:label="@string/app_name">
 (略)
 <service android:name=".MyIntentService"/>
</application>

0 件のコメント:

コメントを投稿