2011年6月1日水曜日

[Android]Serviceのライフサイクルの動作確認

ググればライフサイクルのフローチャートが出てくるだけど、念のため動作確認してみた。想定していたのと違う挙動をしたパターンがいくつかあった。

テストコード

基本的にはAIDLを使ったServiceを作ってるだけ。テスト内容に合わせてコメントアウトしたり。
ITestService.aidl

package local.ServiceLifecycle;

interface ITestService {
int add(int x, int y);
}

TestService.java

ログ取ってるだけですね。

package local.ServiceLifecycle;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class TestService extends Service {
private ITestService.Stub binder = new ITestService.Stub() {
public int add(int x, int y) throws RemoteException {
return x + y;
}
};

@Override
public void onCreate() {
Log.i("ServiceLifecycle", "onCreate");
super.onCreate();
}

@Override
public void onStart(Intent intent, int startId) {
Log.i("ServiceLifecycle", "onStart");
super.onStart(intent, startId);
}

@Override
public IBinder onBind(Intent arg0) {
Log.i("ServiceLifecycle", "onBind");
return binder;
}

@Override
public boolean onUnbind(Intent intent) {
Log.i("ServiceLifecycle", "onUnbind");
super.onUnbind(intent);
return true;
}

@Override
public void onRebind(Intent intent) {
Log.i("ServiceLifecycle", "onRebind");
super.onRebind(intent);
}

@Override
public void onDestroy() {
Log.i("ServiceLifecycle", "onDestroy");
super.onDestroy();
}
}

MainActivity.java

こちらもServiceを起動/終了とログ取りだけ。

package local.ServiceLifecycle;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
private Intent intent;
private ITestService binder;
private ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("ServiceLifecycle", "onServiceConnected");
binder = ITestService.Stub.asInterface(service);
}

public void onServiceDisconnected(ComponentName name) {
Log.i("ServiceLifecycle", "onServiceDisconnected");
}
};

@Override
public void onCreate(Bundle savedInstanceState) {
Log.i("ServiceLifecycle", "Main onCreate");

super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button btn = (Button)findViewById(R.id.Button01);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
unbindService(conn);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
});

intent = new Intent(this, TestService.class);
}

@Override
protected void onStart() {
Log.i("ServiceLifecycle", "Main onStart");

startService(intent);
bindService(intent, conn, BIND_AUTO_CREATE);
super.onStart();
}

@Override
protected void onStop() {
Log.i("ServiceLifecycle", "Main onStop");

unbindService(conn);
stopService(intent);
super.onStop();
}

@Override
protected void onDestroy() {
Log.i("ServiceLifecycle", "Main onDestroy");
super.onDestroy();
}
}

AndroidManifest.xml

<Application>要素内に以下を追加。

<service android:name="TestService">
<intent-filter>
<action android:name="local.ServiceLifecycle.ITestService" />
</intent-filter>
</service>

結果
普通にstart/stop

1. Activity.startService()
1. Service.onCreate()
2. Service.onStart()
2. Activity.stopService()
1. Service.onDestroy()

start2回

1. Activity.startService()
1. Service.onCreate()
2. Service.onStart()
2. Activity.startService()
1. Service.onStart()
3. Activity.stopService()
1. Service.onDestroy

Service.onStart()が2回呼ばれてる。
普通にbind/unbind、start/stopは使わない

1. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
2. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()

Service.onStart()が呼ばれずにService.onBind()が呼ばれてる。

ServiceConnection.onServiceDisconnected()が呼ばれてないけど、こいつはServiceが意図せずに死んだ時(深刻なエラー)のみ呼ばれるらしい。Service.stopSelf()した場合ですらコールされない。ServiceConnection | Android Developers
普通にbind/unbind、start/stopは使わない、Service.onBind()でnullを返す

1. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
2. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()

onBind()の戻り値がnullの場合は、ServiceConnectionのハンドラが呼ばれないようだ。
bindを2回、start/stopは使わない

1. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
2. Activity.bindService()
3. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()

2回目のActivity.bindService()で何も起こらない。多重bindはブロックするようになっているようだ。
一度unbindしてからbindし直す、onUnbindの戻り値はfalse

1. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
2. Activity.bindService()
3. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()
4. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
5. Activity.bindService()
6. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()

同じことが2回繰り返されるだけ。
一度unbindしてからbindし直す、onUnbindの戻り値はtrue

1. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
2. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()
3. Activity.bindService()
1. Service.onCreate()
2. Service.onBind()
3. ServiceConnection.onServiceConnected()
4. Activity.unbindService()
1. Service.onUnbind()
2. Service.onDestroy()

onUnbindの戻り値がfalseの時と挙動変わらず。Service.onDestroy()が走ってしまっているので、わからないでもない。
startしてからbind/unbind

1. Activity.startService()
1. Service.onCreate()
2. Activity.bindService()
1. Service.onBind()
2. ServiceConnection.onServiceConnected()
3. Activity.unbindService()
1. Service.onUnbind()
4. Activity.stopService()
1. Service.onDestroy()

startしてからbind/unbindすると、unbindしてもonDestroyは呼ばれない。
startしてからbind/unbindを2度繰り返す、onUnbindの戻り値はtrue

1. Activity.startService()
1. Service.onCreate()
2. Activity.bindService()
1. Service.onBind()
2. ServiceConnection.onServiceConnected()
3. Activity.bindService()
1. Service.onRebind()
4. Activity.unbindService()
1. Service.onUnbind()
5. Activity.stopService()
1. Service.onDestroy()

2回目のbindでService.onRebind()が呼ばれてる。
startしてからbindし、unbindせずにstop

1. Activity.startService()
1. Service.onCreate()
2. Activity.bindService()
1. Service.onBind()
2. ServiceConnection.onServiceConnected()
3. Activity.stopService()

unbindせずにstopはできないらしい。
bindしてから1秒後にServiceの方でstop

Service.onBind()にこんなの追加して、1秒後にstopSelf()が呼ばれるように。

AsyncTask<Object, Integer, Object> task = new AsyncTask<Object, Integer, Object>() {
@Override
protected Object doInBackground(Object... params) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Object result) {
Log.i("ServiceLifecycle", "stopSelf");
stopSelf();
}
};
task.execute(null);

1. Activity.startService()
1. Service.onCreate()
2. Activity.bindService()
1. Service.onBind()
2. ServiceConnection.onServiceConnected()
3. Service.stopSelf()

やはりunbindせずにstopはできないらしい。

0 件のコメント:

コメントを投稿