演習のポイントは、サービスを存続させ、あるアクティビティから別のアクティビティに渡すことです。
- アクティビティ A は、サービス S で bindService() を呼び出します。
- S.onBound() が呼び出されました。
- A.serviceConnection.onServiceConnected() が呼び出されます。
- アクティビティ A がアクティビティ B を開始します。
- アクティビティ B は、サービス S で bindService() を呼び出します。
- B.serviceConnection.onServiceConnected() が呼び出されます。5a: onServiceConnected() アクティビティから B が A.finish() を呼び出します。
- アクティビティ A が停止し、その onDestroy() メソッドから unbindService(S) を呼び出しています。
予想される動作: サービス S は、アクティビティ B が unbindService() を呼び出すまで問題なく存在し続けます。
実際の動作:
- S.onUnbind() が呼び出されます。
- S.onDestroy() が呼び出されます。
- B.serviceConnection.onServiceDisconnected() が呼び出されます。
したがって、リンクを破壊し、ドキュメントに矛盾します。
なんで?私は何が欠けていますか?
更新: 解決しました。http://developer.android.com/reference/android/app/Service.htmlから:
サービスは、開始することも、接続をバインドすることもできます。このような場合、サービスが開始されているか、 Context.BIND_AUTO_CREATE フラグを使用して1 つ以上の接続が存在する限り、システムはサービスを実行し続けます。
コードは次のとおりです。
public class A extends Activity {
private final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());
private String serviceClassName;
private ServiceConnection feedConnection;
private Messenger feedMessenger;
private void bind(String argument) {
serviceClassName = TheService.class.getName();
Intent intent = new Intent(serviceClassName);
intent.putExtra(Keys.ACCOUNT, argument);
feedConnection = new FeedConnection();
if (!bindService(intent, feedConnection, Context.BIND_AUTO_CREATE)) {
throw new IllegalStateException("Failed to bind to " + argument);
}
logger.debug("bindService(" + serviceClassName + ") successful");
}
private void forward() {
Intent intentB = new Intent();
intentB.setClassName(B.class.getPackage().getName(), B.class.getName());
intentB.putExtra(Keys.SERVICE_CLASS_NAME, serviceClassName);
startActivity(intentB);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(feedConnection);
}
private class FeedConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
A.this.feedMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName className) {
A.this.feedMessenger = null;
logger.error("Crashed " + Integer.toHexString(hashCode()));
}
}
}
public class B extends Activity {
private final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());
private ServiceConnection feedConnection;
private Messenger feedMessenger;
private A activityA;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindFeed();
}
private void bindFeed() {
Intent startingIntent = getIntent();
String serviceClassName = startingIntent.getStringExtra(Keys.SERVICE_CLASS_NAME);
Intent intent = new Intent(serviceClassName);
feedConnection = new FeedConnection();
// FIXME: BIND_AUTO_CREATE flag is missing
if (!bindService(intent, feedConnection, 0)) {
throw new IllegalStateException("Failed to bind to " + serviceClassName);
}
logger.debug("bindService(" + serviceClassName + ") successful");
}
private class FeedConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
B.this.feedMessenger = new Messenger(service);
logger.debug("bound " + className);
// Finish the previous activity only after the service is bound
activityA.fileList();
}
@Override
public void onServiceDisconnected(ComponentName className) {
B.this.feedMessenger = null;
logger.error("Crashed " + className);
}
}
}