Sabtu, 25 April 2009

Registering for TIME_TICK After a Reboot in Android

Creating a service that will receive TIME_TICK, but also start on boot isn't immediately obvious. It took me a bit to figure out the best way to do it, so I figure it's worth sharing.




To start, you can't register your receiver to get TIME_TICK in the android manifest. The registration for TIME_TICK has to happen in code using Intent.registerReceiver. You can, however, define that your receiver has android.permission.RECEIVE_BOOT_COMPLETED and set your receiver to handle it, which will give you some control on boot. Here's the relevant portion of AndroidManifest.xml:





<application android:icon="@drawable/icon" android:label="@string/app_name"
android:enabled="true" android:debuggable="false">
<activity android:name=".AndroidMain" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="DemoService"></service>
<receiver android:name="DemoReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.TIME_TICK"></action>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>




This isn't enough, however, since your receiver can't register itself to listen to TIME_TICK. Intent.registerReceiver registers for the lifetime of the Intent it's called from. If we register it using the intent created for BOOT_COMPLETED, it's dead as soon as it exits the handler. Therefore, we need to start a background service that will keep running. This service then creates a new instance of the receiver and registers that for TIME_TICK.




DemoReceiver.java:



public class DemoReceiver extends BroadcastReceiver {
static final String LOGGING_TAG = "MyDemo";

@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().compareTo(Intent.ACTION_BOOT_COMPLETED) == 0){
Log.v(LOGGING_TAG, "DemoReceiver.onReceive(ACTION_BOOT_COMPLETED)");
context.startService(new Intent(context, DemoService.class));
}else if(intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0)
Log.v(LOGGING_TAG, "DemoReceiver.onReceive(ACTION_TIME_TICK)");
else
Log.v(LOGGING_TAG, "DemoReceiver.onReceive(" + intent.getAction() + ")");
}
}




DemoService.java:



public class DemoService extends Service {
static final String LOGGING_TAG = "MyDemo";

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onStart(Intent intent, int startId){
super.onStart(intent, startId);
Log.v(LOGGING_TAG, "DemoService.onStart()");
}

@Override
public void onCreate(){
super.onCreate();
Log.v(LOGGING_TAG, "DemoService.onCreate()");

registerReceiver(
new DemoReceiver(),
new IntentFilter(Intent.ACTION_TIME_TICK));
}
}





If this all works correctly, we'll see log messages that look something like:




04-25 21:04:22.580: VERBOSE/MyDemo(182): DemoReceiver.onReceive(ACTION_BOOT_COMPLETED)
04-25 21:04:22.630: VERBOSE/MyDemo(182): DemoService.onCreate()
04-25 21:04:22.650: VERBOSE/MyDemo(182): DemoService.onStart()
04-25 21:05:00.140: VERBOSE/MyDemo(182): DemoReceiver.onReceive(ACTION_TIME_TICK)

Tidak ada komentar:

Posting Komentar