I’m interesting building a simple clock widget here. And I wonder what is the best practice to do it? Most of the time it works fine but some says my clock widget lags behind. Actual time is 10.00am then my widget shows perhaps 9.48am
I have this on my manifest
<receiver android:name="my.package.name.MyClock" android:label="@string/widget_name"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/my_clock" /> </receiver> <service android:name="MyClock$UpdateService" android:label="UpdateService" > <intent-filter> <action android:name="my.package.name.UPDATE" /> </intent-filter> </service>
And this is my main java class
public class MyClock extends AppWidgetProvider {
@Override public void onDisabled(Context context) { super.onDisabled(context); context.stopService(new Intent(context, UpdateService.class)); } @Override public void onEnabled(Context context) { super.onEnabled(context); context.startService(new Intent(UpdateService.ACTION_UPDATE)); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); context.startService(new Intent(UpdateService.ACTION_UPDATE)); } public static final class UpdateService extends Service { static final String ACTION_UPDATE = "my.package.name.UPDATE"; private final static IntentFilter sIntentFilter; private String mMinuteFormat; private String mHourFormat; private Calendar mCalendar; static { sIntentFilter = new IntentFilter(); sIntentFilter.addAction(Intent.ACTION_TIME_TICK); sIntentFilter.addAction(Intent.ACTION_TIMEZONE_CHANGED); sIntentFilter.addAction(Intent.ACTION_TIME_CHANGED); } @Override public void onCreate() { super.onCreate(); reinit(); registerReceiver(mTimeChangedReceiver, sIntentFilter); } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(mTimeChangedReceiver); } @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); reinit(); update(); } @Override public IBinder onBind(Intent intent) { return null; } private void update() { mCalendar.setTimeInMillis(System.currentTimeMillis()); final CharSequence minute = DateFormat.format(mMinuteFormat, mCalendar); final CharSequence hour = DateFormat.format(mHourFormat, mCalendar); RemoteViews views = null; views = new RemoteViews(getPackageName(), R.layout.main); views.setTextViewText(R.id.HOUR, hour); views.setTextViewText(R.id.MINUTE, minute); //Refresh the widget ComponentName widget = new ComponentName(this, MyClock.class); AppWidgetManager manager = AppWidgetManager.getInstance(this); manager.updateAppWidget(widget, views); } private void reinit() { mHourFormat = "hh"; mMinuteFormat = "mm"; } private final BroadcastReceiver mTimeChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_TIME_CHANGED) || action.equals(Intent.ACTION_TIMEZONE_CHANGED)) { reinit(); } update(); } }; } }
What am I missing? Why the widget lags behind?
Can you please help me spot the issue here?
And am I doing correct approach? Using Service not AlarmManager to have clock widget updates each minute?
Regards
Quite a lot of reason that may leads to this problem, but most probably, is the Service is killed by System. There’s no way to prevent a background service being killed by System, only making it foreground service will be safe in most of the time, but the notification icon is very annoying to user.
I think using
AlarmManagerwould be the best, I recently updated my clock widget using this technique too. Since AlarmManager makes broadcast, even your application is killed, it will recreate it before sending.