Android broadcast receiver not firing up for updating AppWidget - android

I am trying to test my app Widget and have registered the receiver in the manifest as follows:
<receiver android:name=".MyUtilityWidget" 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/widget_config" />
</receiver>
The MyUtility code:
public class MyUtilityWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
my Main Code here.... (widget stuff)
}
My widget starts and executes once fine (hence I leave the code out of here). However the broadcast receiver is not working and I receive no broadcasts. In fact LogCat shows the intent is never executed. So, my code block only executes once on apk deployment and never again (widget text shows, but never updates every 30m as I have set).
Config here...
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="146dip"
android:minHeight="72dip"
android:updatePeriodMillis="1800000"
android:initialLayout="#layout/widget_message"
/>
Also updatePeriodMillis cannot be less than 30 minutes? This is a very annoying issue when debugging, as I have to wait around 30 minutes each run to check if the intent fired!
Any help appreciated.

You need to grab hold of your widget via RemoteViews and update it accordingly. It doesn't just update automatically.
Try something like this:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
ComponentName thisWidget = new ComponentName(getApplicationContext(),
MyWidgetProvider.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
final int N =allWidgetIds2.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = allWidgetIds2[i];
RemoteViews widgetView = new RemoteViews(getPackageName(), R.layout.widget_layout);
widgetView.setTextViewText(R.id.some_text_view, "some text");

Related

Android widget PendingIntent stop working when app is killed

I have been looking for a solution for this problem for a week by now.
When my app is running in background, the onclicks event on the widget work as expected.
But when the application is closed (killed by task manager), the widget's PendingIntents stop working.
How is it possible?
I think I have created the widget provider correctly.
Something is missing?
Can someone help me?
Here is my code:
- compileSdk 31
- minSdk 23
- targetSdk 31
- gradle -> "com.android.tools.build:gradle:7.0.4"
Provider class:
public class GPWidgetProvider extends AppWidgetProvider {
private static RemoteViews getRemoteViews(Context context) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent intentHome = new Intent(context, Home.class);
intentHome.setData(Uri.parse(intentHome.toUri(Intent.URI_INTENT_SCHEME)));
intentHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent homePendingIntent = PendingIntent.getActivity(context, 13, intentHome, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.widget_image, homePendingIntent);
return views;
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
RemoteViews views = getRemoteViews(context);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
public static void updateWidget(Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName widget = new ComponentName(context, GPWidgetProvider.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget);
for (int appWidgetId : appWidgetIds) {
RemoteViews views = getRemoteViews(context);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Manifest:
<receiver
android:name="<myPackage>.GPWidgetProvider"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
Thanks in advance.
If an app is killed by e.g. the user force-stopping, all of the services, activities, notifications, and PendingIntents from the app are cancelled. You'll only have an opportunity to recover the next time your app runs (from activity launching, receiving broadcast, etc).
This is why the system warns the user that apps may not behave properly if force-stopped.

How can i update a widget only when i press a button in an activity from within the main app

I have made an app consisting of 5 activities . I just wanted to know how I could update a widget only when I press a button in the present in an activity in the main app
You need a reciever for your widget declared in the manifest.xml:
<receiver
android:label="MyIP Widget"
android:icon="#drawable/ic_launcher"
android:name="Widget" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/example_appwidget_info" />
</receiver>
That block should be inside the application block.
In my example the widget updates upon connectivity state change. You can replace that with a custom intent. And, from your activity, you need to send that intent to update the widget, something like this:
Intent i = new Intent();
i.setAction(CUSTOM_INTENT);
context.sendBroadcast(i);
where
public static final String CUSTOM_INTENT = "jason.wei.custom.intent.action.TEST";
you can pick the name that you want.
And make sure to add the same name in the reciever:
<action android:name="jason.wei.custom.intent.action.TEST" />
UPDATE:
to receive you broadcast, you need this method in your Widget class
public class Widget extends AppWidgetProvider {
...
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context,intent);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
ComponentName thisWidget = new ComponentName(context.getApplicationContext(), Widget.class);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (appWidgetIds != null && appWidgetIds.length > 0) {
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
The code above may look a bit complex but it is needed to update all the instances of your widget (the user may have your widget on different home screens or even at one screen).
As you can see, it calls the onUpdate method, where you set the actions you want to be executed to update the widget:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
//your update code here
}

How add app widget provider class

https://developer.android.com/guide/topics/appwidgets/index.html
It explains how to declare it in Manifest:
<receiver android:name="ExampleAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/example_appwidget_info" /> </receiver>
And later it says how to add class:
public class ExampleAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
// 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, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.appwidget_provider_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
} }
And it says I need to declare the class as a broadcast receiver.
So My question is: I have the receiver in my app, but how do I add the class and declare it as a broadcast receiver?
It would be helpful if someone posted an example code of receiver with class, so I know how to put it together.
I'm sorry if this is a stupid question, I'm just new to this all.
Right from the docs:
The AppWidgetProvider class extends BroadcastReceiver as a convenience
class to handle the App Widget broadcasts. The AppWidgetProvider
receives only the event broadcasts that are relevant to the App
Widget, such as when the App Widget is updated, deleted, enabled, and
disabled.
In other words: Since your ExampleAppWidgetProvider is inheriting from AppWidgetProvider class it's also a BroadcastReceiver since the AppWidgetProvider extends android.content.BroadcastReceiver. So there's no need to declare your class explicity as a broadcast receiver. Furthermore that's what the docs say (once again):
You must declare your AppWidgetProvider class implementation as a
broadcast receiver using the receiver element in the AndroidManifest
And as I see it, you already did that. ;)

Android: AppWidgetProvider cant change the updating interval time

In My application I have to use HomeScreenWidget. And every 2minutes It should update its content. So I tried the following steps
i) create AppWidgetProvider class
public class MainWidget extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Log.i("onUpdate","called");
this.context=context;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
remoteViews.setOnClickPendingIntent(R.id.widget_button,getServerData(context));
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent) {
Log.i("onreceive","called");
this.context=context;
AppWidgetManager manager = AppWidgetManager.getInstance(context);
ComponentName thisWidget = new ComponentName(context, MainWidget.class);
remoteViews.setTextViewText(R.id.widget_tv1,aaa);
remoteViews.setTextViewText(R.id.widget_tv2,bbb);
manager.updateAppWidget(thisWidget, remoteViews);
super.onReceive(context, intent);
}
II) create widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="#layout/widget_layout"
android:minHeight="72dp"
android:minWidth="294dp"
android:updatePeriodMillis="120000">
</appwidget-provider>
iii) Add widget class in Manifest
<receiver android:name=".MainWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
My Widget is updating for every 30 minutes. I want to update the widget every 2 minutes..
Please provide me the best way
When specifying the update frequency in the widget_info.xml, the smallest update interval is 30 min (this is to conserve battery life). If you need a higher frequency of updates you should use the AlarmManager in conjunction with a Service.
Here's a tutorial that seem to use the AlarmManager: http://programmerbruce.blogspot.com/2011/04/simple-complete-app-widget-part-1.html

Android widget onClick isn't working

I honestly have no idea what I'm doing wrong here. I had this working last night, I messed with the code and I'm pretty sure I have it back to where it was yet it simply doesn't do anything when clicked.
Here is my code
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
Log.d(LOG_TAG, "onUpdate(): ");
for (int appWidgetId : appWidgetIds) {
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("market://details?id=com.xx.xx"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT );
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget);
remoteView.setOnClickPendingIntent(R.id.image, pendingIntent);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
I'm simply trying to take the user to the market when the widget is clicked but nothing at all happens.
Is this a simple fix?
OH MY GOD. I've spent about 4-5 hours on this.. just realized what I've done wrong.
I was missing 'appWidgetManager.updateAppWidget(appWidgetId, remoteView);' after my setOnClickPendingIntent.
The joys of programming.
For Handling Click on Home Screen Widget you will need Register an Custom Reviver in manifast as:
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.imranandroid.xxx.xxxx.ACTION_WIDGET_CLICK"/>
<action android:name="android.appwidget.action.APPWIDGET_DELETED"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/widget_info" />
</receiver>
and Attach this action with Widget Layout or with Button:
public class SlientwidgetProvider extends AppWidgetProvider {
public static String ACTION_WIDGET_CLICK= "ActionReceiverClick";
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews rview = new RemoteViews(paramContext.getPackageName(), R.layout.widget_layoutmain);
Intent active = new Intent(paramContext, SlientwidgetProvider.class);
active.setAction(Globfilds.ACTION_WIDGET_CLICK);
///....
you can see full code here for handling click on Home Screen Widgets:
Silenttoggle

Categories

Resources