i have a widget to my application that is refreshed every 10 sec. If i change the language of the phone, the widget stops working. I mean, the textviews do not load the texts until they are refreshed (so after 10sec). I added a functionality that the user can open the app by clicking on the widget (an ImageView). This problem still stays.
This whole problem appears also when I restart the phone. I have to wait 10 secs for the textviews to load the texts, but I cannot click on the widget. I may change this interval to 1 sec, what would solve this issue (making it almost invisible for the user). But like I said, I still cannot click on the widget.
Here is the full AppWidgetProvider class:
public class HelloWidget extends AppWidgetProvider {
public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
private static final int REQUEST_CODE_ONE = 10;
String elso;
public static String MY_WIDGET_UPDATE = "MY_OWN_WIDGET_UPDATE";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
updateAppWidget(context, appWidgetManager, appWidgetId);
Toast.makeText(context, "onUpdate(): " + String.valueOf(i) + " : " + String.valueOf(appWidgetId), Toast.LENGTH_SHORT).show();
}
Intent intent = new Intent(context, UpdateService.class);
context.startService(intent);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
Intent configIntent = new Intent(context, MainActivity.class);
configIntent.setAction(ACTION_WIDGET_CONFIGURE);
PendingIntent configPendingIntent = PendingIntent.getActivity(context, REQUEST_CODE_ONE, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.ImageView01, configPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
Intent myIntent = new Intent(context, UpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTimeInMillis(System.currentTimeMillis());
calendar2.add(Calendar.SECOND, 1);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar2.getTimeInMillis(), 50*1000, pendingIntent);
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if(MY_WIDGET_UPDATE.equals(intent.getAction())){
Bundle extras = intent.getExtras();
if(extras!=null) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), HelloWidget.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
if (appWidgetIds.length > 0) {
new HelloWidget().onUpdate(context, appWidgetManager, appWidgetIds);
}
}
}
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId){
}
}
From this code this is the part that serves for opening the MainActivity.class of the app when the user clicks on the widget:
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
Intent configIntent = new Intent(context, MainActivity.class);
configIntent.setAction(ACTION_WIDGET_CONFIGURE);
PendingIntent configPendingIntent = PendingIntent.getActivity(context, REQUEST_CODE_ONE, configIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.ImageView01, configPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
This is the Manfiest part:
<receiver android:name=".HelloWidget" android:label="#string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/widget_provider" />
</receiver>
And this is the widget_provider.xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="72dip"
android:updatePeriodMillis="86400000"
android:initialLayout="#layout/main"
/>
I have a widget to my application that is refreshed every 10 sec [...]
I may change this interval to 1 sec [...]
In short: That's very bad practice. You should (at maximum) only update every 30 minutes.
By refreshing your Widget every 10 seconds, you kill the battery so fast that nobody will use it. Instead, you could add an "refresh"-button which then manually refreshes the Widget.
Also, in the onUpdate-method, you don't need to call the super-method.
And the onReceive-method does not need to be overridden! The onUpdate-method is automatically called when you use an AppWidgetProvider (not if you use a normal BroadcastReceiver). See here.
Last but not least, you should check if your "call-Activity"-code gets reached and try to debug it with the Log-class. The LogCat-Output might also help solving this.
Can you add this flag
PendingIntent configPendingIntent = PendingIntent.getActivity(context, REQUEST_CODE_ONE, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Also check Logcat for any exception it throws when you click on the widget.
Related
My widget provider has intent with value named id, wchich is equal current day of year. But this intent does not change. If today it is focused on 8th March, tomorrow it will also be focused on this day. And on the next day also and so on. But I need to refresh this intent every day.
MyWidgetProvider.java:
public class MyWidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
int layoutId = R.layout.widget;
Calendar c = Calendar.getInstance();
c.setTime(new Date());
int id = c.get(Calendar.DAY_OF_YEAR);
boolean leap = new GregorianCalendar().isLeapYear(c.get(Calendar.YEAR));
int targetId = id<60?id:id+(leap?0:1);
for (int i:appWidgetIds) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("from", "widget");
intent.putExtra("id", targetId);
intent.putExtra("widgetID", i);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), layoutId);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_relative_main, pendingIntent);
}
}
}
my_widget_provider.xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/widget"
android:minHeight="31dp"
android:minWidth="72dp"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="300000" >
</appwidget-provider>
What is a problem?
SOLUTION:
There was required PendingIntent flag "FLAG_UPDATE_CURRENT":
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
And everything works well!
I have simple app with widget. Widget works good for some time. After open and close another app (e.g. some game for the most cases) my widget stops responding to clicks. Do you know how to fix widget freezing please?
I folowed some similar situation, but with no success: Android widget not responding to touches, Android widget buttons stop working, Android Widget stops working randomly, atc.
My actual Widget.class:
public class Widget extends AppWidgetProvider{
private DBManager dbManager;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
String URI_SCHEME = "A";
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(context, MainOverview.class);
Intent intent2 = new Intent(context, AddFragment.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent2.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetId);
intent2.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent2 = PendingIntent.getActivity(context, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the layout for the App Widget and attach an on-click listener
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.widget_all, pendingIntent);
views.setOnClickPendingIntent(R.id.widget_add, pendingIntent2);
Uri data = Uri.withAppendedPath(
Uri.parse(URI_SCHEME + "://widget/id/")
,String.valueOf(appWidgetId));
intent.setData(data);
intent2.setData(data);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM", Locale.ENGLISH);
final Calendar calendar = new GregorianCalendar();
String text_date = sdf.format(calendar.getTime());
CharSequence sumd = (CharSequence) text_date;
views.setTextViewText(R.id.widget_date, sumd);
dbManager = new DBManager(context);
dbManager.open();
int totalPayed = dbManager.getTotalPayed(text_date);
CharSequence sumw = Integer.toString(totalPayed);
views.setTextViewText(R.id.widget_summary, sumw);
dbManager.close();
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
// Update the widgets via the service
context.startService(intent);
context.startService(intent2);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
}
}
My actual widget_provider.xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/widget"
android:minHeight="40dp"
android:minWidth="110dp"
android:resizeMode="horizontal|vertical"
android:previewImage="#drawable/logo"
android:updatePeriodMillis="36000000" >
</appwidget-provider>
My actual part of AndroidManifest.xml:
<receiver android:name=".Widget"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_provider" />
</receiver>
I am working on an android app with a Widget.
Everything works fine except for one thing.
I debug and code my app on different computers so when I launch the app for the first time i need to reinstall it because of the different debug key. When I try readding my widget after the installation I get the 'problem loading widget' and I need to reboot my phone to get it to work again.
This does not always happen, there are also other strange things that might happen.
My widget name, in the add widget list screen, gets renamed to 'foo.packagename.WidgetName' instead of the Widget Title.
The Widget icon gets replaced by the default android launcher icon
When I try adding the widget and place it on the homescreen, the previewimage gets replaced by a random icon
Beta testers experience the same problems after an update, even with the same key (release version).
Is this an android issue, or is something wrong in my code?
My AppWidgetProvider (partially)
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
SimpleDateFormat fmt = new SimpleDateFormat("EEEE d MMMM");
String date = fmt.format(new Date());
for (int i = 0; i < N; i++) {
RemoteViews remoteViews = updateWidgetListView(context,
appWidgetIds[i], date);
appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds[i], R.id.list);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
#Override
public void onDisabled(Context context) {
Intent intent = new Intent(context, AppService.class);
intent.setAction(AppService.ACTION_UPDATE_WIDGET);
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(sender);
super.onDisabled(context);
}
private RemoteViews updateWidgetListView(Context context, int appWidgetId, String date) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget);
Intent svcIntent = new Intent(context, ListWidgetService.class);
remoteViews.setRemoteAdapter(R.id.list, svcIntent);
remoteViews.setEmptyView(R.id.list, R.id.empty_view);
remoteViews.setTextViewText(R.id.widget_sub_title, date);
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_root, pendingIntent);
return remoteViews;
}
widget_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="250dp"
android:minHeight="110dp"
android:previewImage="#drawable/ic_launcher"
android:initialLayout="#layout/widget"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="0">
I'm trying to create my first AppWidget using the AlarmManager class so that I can update more frequently than every 30 minutes. I followed this tutorial as a basis for setting up my widget, but for some reason I cannot get the updates to begin properly. It appears as I am never receiving any APPWIDGET_ENABLED intents, which would fire off the onEnabled event callback in my AppWidgetProvider.
Here is the manifest definition for my AppWidgetProvider:
<receiver
android:name="com.myapp.android.appwidget.MarketTimingAppWidgetProvider"
android:label="#string/appwidget_markettiming_label">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="#string/appwidget_markettiming_updateintent" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/appwidget_markettiming_info" />
</receiver>
Here is the code for my AppWidgetProvider:
public class MarketTimingAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
Log.d("myLogger", "onUpdate");
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
Log.d("myLogger", "Updating Widget: " + appWidgetId);
updateWidget(context, appWidgetManager, appWidgetId);
}
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
Log.d("myLogger", "onEnabled running");
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(),
1000, createClockIntent(context));
}
public void onDisabled(Context context) {
super.onDisabled(context);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(createClockIntent(context));
}
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
Log.d("myLogger", "Intent Received " + intent.getAction());
String widgetIntent = context.getResources().getString(R.string.appwidget_markettiming_updateintent);
// This code fires when my custom intent is received
if(widgetIntent.equals(intent.getAction())) {
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName());
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
for(int appWidgetId: ids) {
updateWidget(context, appWidgetManager, appWidgetId);
}
}
}
private void updateWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_markettiming);
views.setTextViewText(R.id.widget_text, "Update: " +
DateFormat.getDateTimeInstance(
DateFormat.LONG, DateFormat.LONG).format(new Date()));
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
private PendingIntent createClockIntent(Context context) {
String updateIntent = context.getResources().getString(R.string.appwidget_markettiming_updateintent);
Log.d("myLogger", "my intent: " + updateIntent);
Intent intent = new Intent(updateIntent);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
}
When I look in LogCat the only intent that is ever recieved by my onReceive method is the initial APPWIDGET_UPDATE intent, and the only callback ever executed is the onUpdate callback. I've tried including the APPWIDGET_ENABLED intent in my appwidget intent-filter (although the docs tell me that this should be automatically received by my widget). It didn't work. Is there just something I'm missing here?
There is an error in your manifest. Action name in this element:
<action android:name="#string/appwidget_markettiming_updateintent" />
should be replaced by actual string, not the reference. So it should be something like this:
<action android:name="com.myapp.android.appwidget.action.MARKETTIMING_UPDATE" />
or whatever you have in your values/something.xml inside the <string name="appwidget_markettiming_updateintent"> element.
The problem is that the BroadcastReceiver does not receives the broadcasts from AlarmManager. I've created a project with your code, replaced only this string in manifest (and added the appropriate value to values/strings.xml of course) and all works fine.
In addition, you may want to replace the second parameter of alarmManager.setRepeating() by just System.currentTimeMillis() + 1000 and remove all those extra Calendar-related stuff.
Apparently uninstalling it from the emulator and then re-installing it did the trick. Now when I add a widget the APPWIDGET_ENABLE intent is received, and when I remove it the APPWIDGET_DISABLED intent is fired like I would expect. I'm still having an issue where the alarm manager does not actually fire off my custom Intent like I expect, but that's a separate issue I'll need to research.
I am trying to update a Widget more frequently than the 30 minute restriction imposed by the 1.6docs. After reading nearly every post in SO, and the developer docs, and various other sources, I thought I had got to a point where i could implement it. And so, I tried, and failed. Since then, I have trawled yet more forums and solutions, and I cannot seem to get it to update.
I have an Update class that sets the AlarmManager:
public class Update extends Service{
#Override
public void onStart(Intent intent, int startId) {
String currentTemp = Battery.outputTemp;
String currentLevel = Battery.outputLevel;
String currentCard = Battery.outputCard;
String currentInternal = Battery.memory;
String currentRam = String.valueOf(Battery.outputRam).substring(0, 3) + "MB";
// Change the text in the widget
RemoteViews updateViews = new RemoteViews(
this.getPackageName(), R.layout.main);
//update temp
updateViews.setTextViewText(R.id.batteryTemp, currentTemp);
//update %
updateViews.setTextViewText(R.id.batteryLevel, currentLevel);
//update level
updateViews.setTextViewText(R.id.sdCard, currentCard);
//update internal memory
updateViews.setTextViewText(R.id.internal, currentInternal);
//update ram
updateViews.setTextViewText(R.id.ram, currentRam);
ComponentName thisWidget = new ComponentName(this, Widget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
#Override
public IBinder onBind(Intent intent) {
// no need to bind
return null;
}
}
This has caused my onReceive in my widget class to fire frequently (i have a toast to see when it fires), yet it carries no intent (the toast is meant to display this as they are received but it is blank).
I cannot figure it out (i'm a relative newb-2 months of slow android dev), and appreciate any insight you guys have.
heres my widget class for reference:
public class Widget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
AlarmManager alarmManager;
Intent intent = new Intent(context, Update.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) context
.getSystemService(Context.ALARM_SERVICE);
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
cal.add(Calendar.SECOND, 10);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal
.getTimeInMillis(), 5 * 1000, pendingIntent);
String currentTemp = Battery.outputTemp;
String currentLevel = Battery.outputLevel;
String currentCard = Battery.outputCard;
String currentInternal = Battery.memory;
String currentRam = String.valueOf(Battery.outputRam).substring(0, 3)
+ "MB";
// Change the text in the widget
RemoteViews updateViews = new RemoteViews(context.getPackageName(),
R.layout.main);
// update temp
updateViews.setTextViewText(R.id.batteryTemp, currentTemp);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
// update %
updateViews.setTextViewText(R.id.batteryLevel, currentLevel);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
// update level
updateViews.setTextViewText(R.id.sdCard, currentCard);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
// update internal memory
updateViews.setTextViewText(R.id.internal, currentInternal);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
// update ram
updateViews.setTextViewText(R.id.ram, currentRam);
appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
Toast
.makeText(context, intent.getAction() + context,
Toast.LENGTH_LONG).show();
Bundle extras = intent.getExtras();
if (extras != null) {
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context
.getPackageName(), Widget.class.getName());
int[] appWidgetIds = appWidgetManager
.getAppWidgetIds(thisAppWidget);
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
}
This is my solution, how to automatically update widget more frequently than the 30 minutes. I use AlarmManager. Before you use AlarmManager for refreshing appwidget, make sure you know what you do, because this technique could drain the device's battery.
Read more about widget update in Android doc - especially about updatePeriodMillis parameter.
This is part of my Manifest.xml. I define custom action AUTO_UPDATE.
<receiver android:name=".appwidget.AppWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="AUTO_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="#xml/appwidget_info" />
</receiver>
This is part of my AppWidget.java. In onReceive method, I handle my custom action AUTO_UPDATE. In onEnabled and onDisabled methods, I start/stop alarm.
public class AppWidget extends AppWidgetProvider
{
public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
if(intent.getAction().equals(ACTION_AUTO_UPDATE))
{
// DO SOMETHING
}
...
}
#Override
public void onEnabled(Context context)
{
// start alarm
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.startAlarm();
}
#Override
public void onDisabled(Context context)
{
// stop alarm only if all widgets have been disabled
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidgetComponentName = new ComponentName(context.getPackageName(),getClass().getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidgetComponentName);
if (appWidgetIds.length == 0) {
// stop alarm
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.stopAlarm();
}
}
...
}
This is my AppWidgetAlarm.java, which starts/stops alarm. Alarm manager sends broadcast to AppWidget.
public class AppWidgetAlarm
{
private final int ALARM_ID = 0;
private final int INTERVAL_MILLIS = 10000;
private Context mContext;
public AppWidgetAlarm(Context context)
{
mContext = context;
}
public void startAlarm()
{
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS);
Intent alarmIntent=new Intent(mContext, AppWidget.class);
alarmIntent.setAction(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
// RTC does not wake the device up
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), INTERVAL_MILLIS, pendingIntent);
}
public void stopAlarm()
{
Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
I have an Update class that sets the AlarmManager:
No, you don't. AlarmManager appears nowhere in the code snippet.
You do have a reference to AlarmManager in the second code snippet. Problems there include:
You are setting a new repeating alarm every time the app widget updates
You are setting a 5 second frequency on the alarm, which is utter insanity
You are setting a 5 second frequency on a _WAKEUP alarm, which I think is grounds for your arrest in some jurisdictions
You have a pointless onReceive() method, even ignoring the temporary Toast
You are assuming that there will be an action string on the Intent in your Toast, but you do not specify an action string when you create the Intent that you put in the PendingIntent for the alarm
Your code refers to what I presume are static data members on a Battery class, but it is rather likely those are all empty/null... or at least they would be, if you had a sane frequency on the alarm
Thanks for this example - I also had problems using a later Android version.
This post made it work for me:
widget case that doesn't work (see the answer from Larry Schiefer).
So substituting for this from the code above:
Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
with this from the ref:
Intent alarmIntent=new Intent(mContext, MyWidget.class);
alarmIntent.setAction(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
did the job.
A little bit modified version of petrnohejl's solution. This one is working in my project. (written in kotlin):
This is part of the Manifest.xml. I added the following actions: AUTO_UPDATE, APPWIDGET_UPDATE, APPWIDGET_ENABLED, APWIDGET_DISABLED.
<receiver android:name=".AppWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED"/>
</intent-filter>
<intent-filter>
<action android:name="ACTION_AUTO_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/appwidget_info"/>
</receiver>
This is part of the AppWidget.kt. Here I implemented the onUpdate(), onEnabled(), onDisabled(), onReceive() functions.
class AppWidget: AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) { // Enter relevant functionality for when the first widget is created
// start alarm
val appWidgetAlarm = AppWidgetAlarm(context.applicationContext)
appWidgetAlarm.startAlarm()
}
override fun onDisabled(context: Context) { // Enter relevant functionality for when the last widget is disabled
// stop alarm only if all widgets have been disabled
val appWidgetManager = AppWidgetManager.getInstance(context)
if (appWidgetIds.isEmpty()) {
// stop alarm
val appWidgetAlarm = AppWidgetAlarm(context.getApplicationContext())
appWidgetAlarm.stopAlarm()
}
}
companion object {
val ACTION_AUTO_UPDATE = "AUTO_UPDATE"
fun updateAppWidget(context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int) {
val widgetText = Random.nextInt(0, 100).toString()
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.appwidget)
views.setTextViewText(R.id.widget_text, widgetText)
// Instruct the widget manager to update the widget
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_text)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
// Do something
/*if (intent!!.action == ACTION_AUTO_UPDATE) {
// DO SOMETHING
}*/
}
}
And this is the AppWidgetAlarm.kt. Here it is my main modification. The answers didn't help me, but it is working. I set here a repeating alarm. (https://developer.android.com/training/scheduling/alarms)
class AppWidgetAlarm(private val context: Context?) {
private val ALARM_ID = 0
private val INTERVAL_MILLIS : Long = 10000
fun startAlarm() {
val calendar: Calendar = Calendar.getInstance()
calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS.toInt())
val alarmIntent = Intent(context, AppWidget::class.java).let { intent ->
//intent.action = AppWidget.ACTION_AUTO_UPDATE
PendingIntent.getBroadcast(context, 0, intent, 0)
}
with(context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
setRepeating(AlarmManager.RTC,calendar.timeInMillis, INTERVAL_MILLIS ,alarmIntent)
}
}
fun stopAlarm() {
val alarmIntent = Intent(AppWidget.ACTION_AUTO_UPDATE)
val pendingIntent = PendingIntent.getBroadcast(context, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)
val alarmManager = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.cancel(pendingIntent)
}
}