前回に続いてAIDLのお話です。今回はCallbackしてみます。
流れとしては、
- ActivityでServiceをBind
- ServiceのCallback登録Interfaceをコール
- Serviceに実装したCallback登録Interfaceで、受け取ったCallback情報をリストに登録
- Callbackリストを参照して登録されているCallback Interfaceをコール
- Activityに実装したCallback Interfaceでなんかする
みたいな感じです。
図にするとこんな感じ。

続きを読む…
タイトルにあるとおり、Activity – Service間の通信のお話です。
andoridでは、簡単にActivityからServiceのメソッドを実行することができます。
- AIDLファイルにIPCのインターフェイスを記述する
- Serviceにインターフェイスを実装する
- ActivityからServiceにBindし、インターフェイスを叩く
たったこれだけです。
サンプルとして、テキストボックスに入力された値をServiceで加算するプログラムを作ってみます。
こんな感じ。

続きを読む…
androidはユーザがアプリプロセスの終了を意識しない作りとなっています。
戻るボタンやホームボタンを押すとホーム画面に戻り、不要となったアプリプロセスはOSがテキトーなタイミングで殺します。
OSに殺されたくないときはServiceを作ってあげれば良いのですが、OSが勝手にServiceプロセスを再起動することがあるっぽいです。
Serviceでタイマーを仕掛けて周期的に処理を行っていたのですが、この周期的な処理が途切れてしまう現象が発生しました。
DDMSでプロセスをチェックしてみると、なんとタイマースレッドが死んでました ?(^o^)/
onCreate(), onStart(), onDestroy()にログを仕掛けて放置してみると、何も操作していないのにonCreate()がコールされてる・・・。
しかも、元のServiceプロセスのonDestroy()や新しいServiceプロセスのonStart()はなしです。
android:process属性を設定して別プロセスにしてみましたが、あえなくお亡くなりに。
まとめると以下のような感じ。
- ServiceプロセスはOSが再起動することがある。
- Serviceプロセスの再起動時には、新しいプロセスのonCreate()のみが呼ばれる。
- Serviceプロセスを別プロセスとしても再起動が発生する。
ちなみに、音楽プレイヤーとかのガリガリ動く物は再起動されることはないと思います。
長時間アイドル状態となっているから殺されるのでしょう。
前回はViewのonClickリスナにPendingIntentを仕掛けることによって、AppWidgetのクリックイベントを拾うことができました。
複数のWidgetを配置している場合には、どのWidgetがクリックされたかを判断する必要があります。
Intent.setData()を使用してActivityにAppWidgetIDを渡してあげればOKです。
public class SampleWidgetProvider extends AppWidgetProvider {
public static final Uri CONTENT_URI = Uri.parse("content://jp.xfutures.android.sample");
public void onUpdate(
Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds
){
for(int id : appWidgetIds){
// 起動するActivityのIntentを作成する
Intent intent = new Intent(context, SampleWidgetActivity.class);
// AppWidget IDを設定する
Uri uri = ContentUris.withAppendedId(CONTENT_URI, id);
intent.setData(uri);
// PendingIntentを取得する
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// onClickリスナを設定する
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
// AppWidgetを更新する
appWidgetManager.updateAppWidget(id, views);
}
}
}
受けるとる時はIntent.getData()ですね。
public class SampleWidgetActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.onclick);
// AppWidget IDを取得する
Uri uri = getIntent().getData();
int id = (int)ContentUris.parseId(uri);
// AppWidget IDをTextViewに設定する
TextView view = (TextView)findViewById(R.id.TextViewID);
view.setText(String.format("WidgetID is %d.", id));
}
}
AndroidSample2009062101.zip
AppWidget上でのクリックイベントは、公式ドキュメントにあるようにPendingIntentを使って取得することができます。
AppWidgetProvider.onUpdateの中でビューをアップデートするときに、そのビューに対してPendingIntentを仕掛けてあげればOKです。
public class SampleWidgetProvider extends AppWidgetProvider {
public void onUpdate(
Context context,
AppWidgetManager appWidgetManager,
int[] appWidgetIds
){
for(int id : appWidgetIds){
// 起動するActivityのIntentを作成する
Intent intent = new Intent(context, SampleWidgetActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// onClickリスナを設定する
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
// AppWidgetを更新する
appWidgetManager.updateAppWidget(id, views);
}
}
}