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)
curious why you register the TIME_TICK action on the receiver in the manifest and not on the service?
ReplyDeleteBTW is it just me (as a newbie to Android) or is the whole programming model just a bit "clunky" and non-intuitive?
ReplyDelete:)
Doh ... ignore my 1st comment, I get it now ...
ReplyDeleteit's the broadcast receiver that gets the ticks ... hence its the target of the intent filter ...
I should RTFC ... I still think my 2nd comment is germain ... :)
can use TIME_TICK for second?
ReplyDeleteintent.getAction().compareTo(Intent.ACTION_BOOT_COMPLETED) == 0
ReplyDeleteshould be written as
intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)
Nice, but how do you stop the service and the notifications that keep coming every minute without uninstalling the application?
ReplyDeleteOnce the service is bound to the registered receiver, I could not stop the service once started because it was bound to the registered receiver even when I called stopService(intent) with a static intent from the same app that started the service.
when I use TIME_TICK for minute then missing one minute each hour
ReplyDeletewhy missing one minute log report in each hour ?
I have a error? help me please
ReplyDeletejava.lang.ClassNotFoundException: Didn't find class "com.example.AndroidMain" on path: DexPathList[[zip file "/data/app/com.example-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example-1, /vendor/lib, /system/lib]]
Same problem for me. AndroidMain does not exist in my example:
ReplyDelete```
08-20 01:35:28.660 4494 4494 E AndroidRuntime: java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.wifi/com.example.wifi.AndroidMain}: java.lang.ClassNotFoundException: Didn't find class "com.example.wifi.AndroidMain" on path: DexPathList[[zip file "/data/app/com.example.wifi-wfD48gjtZGqsPqHSkwOI-w==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.wifi-wfD48gjtZGqsPqHSkwOI-w==/lib/arm64, /system/lib64]]
```