I have an issue with my clock widget. I run a Service to refresh it when needed (on USER_PRESENT event and each minute while screen on), but this Service seems to be killed after some time, randomly, and is not restarted.
I have set notifications in my Service's onDestroy() and onLowMemory() methods but they are never called.
I never call the stopSelf() method.
The widget is no longer visible in launched application list into the system.
When the WidgetProvider naturally updates (every 6 hours), the service is restarted and all works perfectly for a moment.
Here is my code :
(note that the Application in the manifest is not named nor created in the code. Only the provider and service. don't know if it's correct)
Widget Provider :
public class WidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] ids) {
super.onUpdate(context, appWidgetManager, ids);
Intent serviceIntent = new Intent(context.getApplicationContext(), WidgetService.class);
context.startService(serviceIntent);
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
Intent serviceIntent = new Intent(context.getApplicationContext(), WidgetService.class);
context.stopService(serviceIntent);
super.onDisabled(context);
}
}
The Service :
public class WidgetService extends Service {
private static String LOG = WidgetService.class.getSimpleName();
public Hashtable<Integer, ClockView> views = new Hashtable<Integer, ClockView>();
AppWidgetManager man;
private static WidgetService self;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Toast.makeText(this, LOG+" configuration change", Toast.LENGTH_LONG).show();
}
#Override
public void onCreate() {
super.onCreate();
man = AppWidgetManager.getInstance(this);
self = this;
// Registering Intent for screen state
...
registerReceiver(screenoffReceiver, filter);
// Registering Intent for click event
...
UpdateAllWidgets();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
UpdateAllWidgets();
return START_STICKY;
}
#Override
public void onDestroy() {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.holder)
.setContentTitle("WidgetClock")
.setContentText("Destroyed at "+Calendar.getInstance().getTime());
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, mBuilder.build());
super.onDestroy();
}
#Override
public void onLowMemory() {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.holder)
.setContentTitle("WidgetClock")
.setContentText("LowMemory at "+Calendar.getInstance().getTime());
((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)).notify(1, mBuilder.build());
super.onLowMemory();
}
public void onScreenOff() {
}
private void onScreenOn() {
}
public void onUserPresent() {
}
public void UpdateAllWidgets() {
views.clear();
int[] ids = man.getAppWidgetIds(new ComponentName(this, WidgetProvider.class));
for (int id : ids)
createViewIfNecessary(id);
}
private void createViewIfNecessary(int id) {
if (!views.containsKey(id)) {
ClockView view = new ClockView(this, id);
views.put(id, view);
}
}
public static Context getApp(){
return self;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
The manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.widgetclock"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:clickable="true" >
<service android:name="WidgetService"></service>
<receiver android:name="WidgetProvider"
android:clickable="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_provider_file" />
</receiver>
</application>
The widget provider config XML
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dip"
android:minHeight="125dip"
android:updatePeriodMillis="21600000"
android:initialLayout="#layout/widget_main">
</appwidget-provider>
Related
I saw similar questions here on SO, but nothing seems to work in my case...
I created an appwidget with an AdapterViewFlipper (Simple ViewAnimator that will animate between two or more views that have been added to it). The appwidget has a Next button that enables the user to navigate to the next view on the widget.
It all works fine when I first add the appwidget. But if the smartphone reboots, the Next button of the widget no longer works on my Samsung S4 (the method onReceive is called, but nothings happens, it doesn't navigate to the next view and is stuck at the first view). I have to delete the widget and add it again in order for it to work...
I suspect that it is a problem of Touchwiz since I tested it on another phone (Moto G) and it worked fine.
Here are some portions of my code :
AppWidgetProvider
public class AppWidgetProvider extends AppWidgetProvider {
public static final String NEXT_ACTION = VersionUtil.getPackageName() + ".action.NEXT";
private static final String TAG = DailyAppWidget.class.getSimpleName();
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId, colorValue);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId, int primaryColor) {
Intent intent = new Intent(context, ViewFlipperWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
// Instantiate the RemoteViews object for the app widget layout.
RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.app_widget);
// open the activity from the widget
Intent intentApp = new Intent(context, MainActivity.class);
intentApp.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intentApp, 0);
rv.setOnClickPendingIntent(R.id.widget_title, pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
rv.setRemoteAdapter(R.id.adapter_flipper, intent);
} else {
rv.setRemoteAdapter(appWidgetId, R.id.adapter_flipper, intent);
}
// Bind the click intent for the next button on the widget
final Intent nextIntent = new Intent(context,
AppWidgetProvider.class);
nextIntent.setAction(AppWidgetProvider.NEXT_ACTION);
nextIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
final PendingIntent nextPendingIntent = PendingIntent
.getBroadcast(context, 0, nextIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
rv.setOnClickPendingIntent(R.id.widget_btn_next, nextPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, mRemoteViews);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NEXT_ACTION)) {
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.daily_app_widget);
rv.showNext(R.id.adapter_flipper);
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
Log.e(TAG, "onReceive APPWIDGET ID " + appWidgetId);
AppWidgetManager.getInstance(context).partiallyUpdateAppWidget(
appWidgetId, rv);
}
super.onReceive(context, intent);
}
Service
public class FlipperRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private Context mContext;
private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private static final String TAG = "FILPPERWIDGET";
public FlipperRemoteViewsFactory(Context context, Intent intent) {
mContext = context;
mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
//... get the data
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate()");
}
#Override
public void onDataSetChanged() {
Log.i(TAG, "onDataSetChanged()");
}
#Override
public void onDestroy() {
}
#Override
public int getCount() {
//... return size of dataset
}
#Override
public RemoteViews getViewAt(int position) {
Log.i(TAG, "getViewAt()" + position);
RemoteViews page = new RemoteViews(mContext.getPackageName(), R.layout.app_widget_item);
//... set the data on the layout
return page;
}
#Override
public RemoteViews getLoadingView() {
Log.i(TAG, "getLoadingView()");
return new RemoteViews(mContext.getPackageName(), R.layout.appwidget_loading);
}
#Override
public int getViewTypeCount() {
Log.i(TAG, "getViewTypeCount()");
return 1;
}
#Override
public long getItemId(int position) {
Log.i(TAG, "getItemId()");
return position;
}
#Override
public boolean hasStableIds() {
Log.i(TAG, "hasStableIds()");
return true;
}
}
Manifest
<receiver android:name=".AppWidgetProvider"
android:label="#string/app_name"
android:enabled="#bool/is_at_least_12_api">
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/app_widget_info" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
</receiver>
<!-- Service serving the RemoteViews to the collection widget -->
<service android:name=".ViewFlipperWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS"
android:exported="false" />
app wigdet info
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="#layout/app_widget"
android:initialLayout="#layout/app_widget"
android:minHeight="110dp"
android:minWidth="250dp"
android:previewImage="#drawable/widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="14400000"
android:widgetCategory="home_screen" />
Any help would be appreciated !
Depends on the launcher, there is no guarantee that your AppWidget will be updated immediately after the device started. It may be refreshed immeidately, or wait till the updatePeriodMillis passed after system started.
To solve your problem, define a BroadcastReceiver that will trigger the update of AppWidget after the reboot.
In AndroidManifest.xml, define the BootReceiver to get the boot_complete message.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
And define the BootReceiver.java to start your AppWidgetUpdateService
public class BootReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent){
//start appwidget update service
}
}
I am currently developing an Android project which makes use of a Homescreen Widget to display data to the user. The view that I used in the Widget is a ListView. Below are my codes:
WidgetService Class
public class WidgetService extends RemoteViewsService
{
#Override
public RemoteViewsFactory onGetViewFactory(Intent intent)
{
return (new WidgetRemoteViewsFactory(this.getApplicationContext(), intent));
}
}
WidgetProvider Class
public class WidgetProvider extends AppWidgetProvider
{
#Override
public void onDeleted(Context context, int[] appWidgetIds)
{
super.onDeleted(context, appWidgetIds);
}
#Override
public void onDisabled(Context context)
{
super.onDisabled(context);
}
#Override
public void onEnabled(Context context)
{
super.onEnabled(context);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
for(int i=0;i<appWidgetIds.length;i++)
{
RemoteViews rv = new RemoteViews(context.getPackageName(),
R.layout.widget);
Intent intent = new Intent(context, WidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
appWidgetIds[i]);
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(R.id.widgetListView, intent);
appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
WidgetRemoteViewsFactory Class
public class WidgetRemoteViewsFactory implements RemoteViewsFactory
{
private Context context = null;
private int appWidgetId;
private List<String> widgetList = new ArrayList<String>();
private DBHelper dbhelper;
public WidgetRemoteViewsFactory(Context context, Intent intent)
{
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
Log.d("AppWidgetId", String.valueOf(appWidgetId));
dbhelper = new DBHelper(this.context);
}
private void updateWidgetListView()
{
String[] widgetFruitsArray = dbhelper.retrieveFruitsList();
List<String> convertedToList = new ArrayList<String>(Arrays.asList(widgetFruitsArray));
this.widgetList = convertedToList;
}
#Override
public int getCount()
{
return widgetList.size();
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public RemoteViews getLoadingView()
{
// TODO Auto-generated method stub
return null;
}
#Override
public RemoteViews getViewAt(int position)
{
Log.d("WidgetCreatingView", "WidgetCreatingView");
RemoteViews remoteView = new RemoteViews(context.getPackageName(),
R.layout.listview_row_item);
Log.d("Loading", widgetList.get(position));
remoteView.setTextViewText(R.id.listTV, widgetList.get(position));
return remoteView;
}
#Override
public int getViewTypeCount()
{
// TODO Auto-generated method stub
return 0;
}
#Override
public boolean hasStableIds()
{
// TODO Auto-generated method stub
return false;
}
#Override
public void onCreate()
{
// TODO Auto-generated method stub
updateWidgetListView();
}
#Override
public void onDataSetChanged()
{
// TODO Auto-generated method stub
updateWidgetListView();
}
#Override
public void onDestroy()
{
// TODO Auto-generated method stub
widgetList.clear();
dbhelper.close();
}
}
Android Manifest File
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.listviewwithdb"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/MyTheme.Light" >
<activity
android:name="com.example.listviewwithdb.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.example.listviewwithdb.WidgetProvider" >
<intent-filter >
<action
android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widgetinfo" />
</receiver>
<service
android:name="com.example.listviewwithdb.WidgetService"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
</application>
</manifest>
The problem is that I can add the widget into the homescreen, but it displays the list of item in the listview with a "Loading.." message in it, I tried logging the values at getViewAt() as shown above and it displays the content that I want successfully. Is there anything that I'm missing in my codes that is causing the issue? Thanks for the help in advance
I have found out the issue. It turns out that I need to return the number of views, in which my case is 1, that I have in getViewTypeCount() in my WidgetRemoteViewsFactory class.
I have this Service class:
public class BluetoothService extends Service {
private static Activity mActivity;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
this.registerReceiver(bluetoothReceiver, intentFilter);
}
#Override
public void onDestroy() {
if (bluetoothReceiver != null) {
this.unregisterReceiver(bluetoothReceiver);
}
}
#Override
public void onStart(Intent intent, int startid) {
//
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public static BroadcastReceiver bluetoothReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
TextView tvStatus = (TextView) mActivity.findViewById(R.id.tvtatus);
Messaging.appendMessage(tvStatus, Bluetooth.getDeviceState(state));
if (Bluetooth.isBluetoothEnabled()) {
Messaging.appendMessage(tvStatus, Bluetooth.showMessage());
}
}
}
};
}
And in my Activity class, I have this:
public class MainActivity extends Activity {
private TextView tvStatus;
private Intent intentBluetooth;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvStatus = (TextView)findViewById(R.id.tvtatus);
intentBluetooth = new Intent(this, BluetoothService.class);
startService(intentBluetooth);
}
}
The BroadcastReceiver method (bluetoothReceiver) in the Service class is never called. I don't know why. If I have the IntentFilter and the BroadcastReceiver codes above all in an Activity, then it works - but not in a [separate] Service. I'm stumped.
My AndroidManifest.xml is:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.onegoal.androidexample"
android:versionCode="1"
android:versionName="1.0.0"
android:installLocation="auto"
android:hardwareAccelerated="true">
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:debuggable="true" >
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".BluetoothService">
</service>
</application>
</manifest>
I'm new to Android so what I'm doing may not be the best. Hope someone can help me.
maybe the fact that your receiver is static causing the problem.
BroadcastReceiver should never be static. it can cause lots of problems.
other really bad design problem with your code - holding reference to activity inside service, and using it to modify views is really wrong thing to do. it can cause easily to memory leek.
the right why to communicate between Service and Activity is by implement android's Messanger, or sending broadcasts between them via BroadcastReceiver.
if you'll listen to my advice - you won't be have to make your receiver static (I guess you've made it static only because you are using the mActivity static instance inside)
and I'm pretty sure it will solve your problem
you can read about Messanger here: http://developer.android.com/reference/android/os/Messenger.html
sure you'll find lots of usage examples in the net.
example of broadcasting updates to the activity from service:
public class MyService extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
this.registerReceiver(bluetoothReceiver, intentFilter);
}
#Override
public void onDestroy() {
if (bluetoothReceiver != null) {
this.unregisterReceiver(bluetoothReceiver);
}
super.onDestroy();
}
public BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
updateUIWithNewState(state);
}
}
};
protected void updateUIWithNewState(int state) {
Intent intent = new Intent("serviceUpdateReceivedAction");
intent.putExtra("state", state);
sendBroadcast(intent);
}
}
and that's the activity:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
#Override
protected void onResume() {
super.onResume();
registerReceiver(mServiceUpdatesReceiver, new IntentFilter("serviceUpdateReceivedAction"));
}
#Override
protected void onPause() {
unregisterReceiver(mServiceUpdatesReceiver);
super.onPause();
}
private BroadcastReceiver mServiceUpdatesReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra("state", -1);
// do what ever you want in the UI according to the state
}
};
}
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 AlarmManager would 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.
I need to make a widget which, once clicked, would start a service. Service would perform a certain action, change the widgets picture, play a sound, etc., and stop.
AppWidgetProvider:
public class WidgetActivity extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Intent intent = new Intent(context.getApplicationContext(), SilentService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getService(
context.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.LinLayWiget, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
context.startService(intent);
}
}
service:
public class SilentService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "I'm Alive!", 1500).show();
MediaPlayer mpl = MediaPlayer.create(this, R.raw.enter );
mpl.start();
}
#Override
public void onDestroy() {
//code to execute when the service is shutting down
}
#Override
public void onStart(Intent intent, int startid) {
//code to execute when the service is starting up
}
}
manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="FX.Widget"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<receiver android:name="widget.cam.com.WidgetActivity" android:label="FXMaster" android:icon="#drawable/assiconwi">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_ENABLED"/>
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widgetprovider" />
</receiver>
<service
android:enabled="true"
android:name=".SilentService">
</service>
</application>
</manifest>
But once I click on the widget, nothing happens... any ideas why?
Thanks!