I'm working on an Android application which includes a widget. The main interface of the app is a simple activity, but some of the things users can do in the activity make it necessary to update the widget - i.e. run its onUpdate method.
How can I trigger this method from the activity? Looking at other questions, I've been able to write code which changes its layout, but it doesn't seem to run onUpdate (since I'm just left with the empty layout and none of the data which is added during onUpdate).
Any ideas or code samples very much appreciated!
I am still pretty new to Android, but I accomplished this with three steps:
First, I put the contents of my AppWidgetProvider.onUpdate in a method (myUpdate(Context)).
Second, I overrode AppWidgetProvider.onReceive() to look something like this:
public void onReceive(final Context context, final Intent intent)
{
super.onReceive(context, intent);
if (MY_PUBLIC_STATIC_STRING.equals(intent.getAction()))
{
myUpdate(context);
}
}
Third, from my other activity, I just send a generic broadcast with the action set on the intent.
Intent updateWidgetIntent = new Intent(context, MyWidget.class);
updateWidgetIntent.setAction(MyWidget.MY_PUBLIC_STATIC_STRING);
context.sendBroadcast(updateWidgetIntent);
This does have the down side of having to find the AppWidgetManager yourself from the context and the app widget ids, instead of the nice interface onUpdate gives you. So I am skeptical that this is the right approach. Best of luck.
myUpdate(Context) starts like this:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds =
appWidgetManager.getAppWidgetIds(new ComponentName(context, this.getClass()));
Related
What is the use of
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
on the following Intent in an AppWidgetProvider class (see code below)
According to the CommonsWare book, the reason is:
While your application has access to your RemoteViewsService Class object, the app widget host will not, and so we need something that will work across process boundaries. You could elect to add your own to the RemoteViewsService and use an Intent based on that, but that would make your service more publicly visible than you might want.
Source: The Busy Coder's Guide to Android Development
https://commonsware.com/Android/
But when I delete this line, nothing changes. The widget still works.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
[...]
Intent serviceIntent = new Intent(context, WidgetService.class);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
views.setRemoteAdapter(R.id.stack_view, serviceIntent);
views.setEmptyView(R.id.stack_view, R.id.empty_view);
[...]
appWidgetManager.updateAppWidget(appWidgetId, views);
}
I figured it out.
If you don't use setData, the system can not distinguish between different service intents, which causes it to call onGetViewFactory only once for multiple widgets and send the same intent to all of them.
If you for example send the app widget id to your RemoteViewsService and from their to your RemoteViewsFactory and display it in every item, it will display the same id for all instances of the widget, if you don't use setData.
I have a widget whose content is very similar to what is seen in the actual app, i.e. images and text just on a smaller scale.
I am using the following code to make the widget update after the activity UI updates - only it is not working and the widget it not updating:
Intent i = new Intent(mContext, ExtensionOfAppWidgetProvider.class);
i.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
mContext.sendBroadcast(i);
I cannot get the onUpdate() of the AppWidgetProvider class to be called without removing the widget and then placing it back on the homescreen.
Any help is appreciated.
Thanks.
Here was the culprit...a couple lines of code were missing from the onReceive() of my AppWidgetProvider class.
AppWidgetManager mgr = AppWidgetManager.getInstance(context);
int[] ids = mgr.getAppWidgetIds(new ComponentName(context, PromoStackWidgetProvider.class));
for(int id : ids) {
mgr.notifyAppWidgetViewDataChanged(id, R.id.stack_view);
}
Make sure that your widget has itself as a registered broadcast reciever in your AndroidManifest.xml
i am making an appwidget and i have problems with click event, which is lost when system kills the widget's process and later restarts it. this also happens after screen rotate.
building against SDK version 7 and running on emulator (2.1) and a real device with 2.3.3.
my onUpdate method:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int wid : appWidgetIds) {
Log.i(TAG, "onUpdate widget #" + wid);
Intent intent = new Intent(context, MyClass.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, wid);
PendingIntent clickIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget);
widget.setOnClickPendingIntent(R.id.widget_layout, clickIntent);
appWidgetManager.updateAppWidget(wid, widget);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
where R.id.widget_layout is id of linear layout of the appwidget. i tried to add this click event also to a textview, but with same result.
i am fighting this problem for several days and i found some people with this same problem, but no solution works for me :( i also tried different pending intent flags without any success.
second problem is, when i add another appwidget on home screen, it does not react to click events. in logcat i see the message from onUpdate method "onUpdate widget #xy", but the appwidget does not react to clicks. only the first appwidget placed on home screen reacts to clicks, but only for some time. any ideas?
When you say the first widget stops responding to clicks, do you mean that the onUpdate method is not being called? Perhaps put some code in onEnabled(Context context) to see if that's being called instead, and if so, put whatever logic is necessary in that function. Also, you can catch intents via the onReceive method (found at the same link) to see which ones your widget is actually receiving.
Also, ensure that the Context that you have the receiver running in (the one that gets passed to this function) is an Application or Service, and not an Activity, or the reference to it may not persist.
You must also make sure that every time you update the widget with a RemoteViews object, you send all of the data needed to fully reconstruct the widget. This is because on, e.g., screen rotation, the system doesn't have anything to reconstruct the widget with beside the very latest RemoteViews you passed it.
i have one widget in which there are two buttons and one service class in which i have two methods on clikcing of button i want to call the methods in service class.
any reference or code example?
how can i do it?
thankx
I'm guessing that your question pertains to appWidgets. If not, the answer below will probably be less useful, although you can still adapt part of it to your own use, I think.
First declare some action(s), like this:
public static final String ACTION_HIDE_GUIDE_OVERLAY = "dk.something.appwidget.calendar.guide.hide";
Use the action(s) to declare an Intent and a PendingIntent:
Intent intent = new Intent(context, CalendarService.class);
intent.setAction(CalendarService.ACTION_HIDE_GUIDE_OVERLAY);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent buttonPendingIntent1 = PendingIntent.getService(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then register the pendingIntent with the RemoteView for your widget:
views.setOnClickPendingIntent(R.id.calendar_button_1, buttonPendingIntent1);
Finally, in the onStartCommand or onHandleIntent of your service, examine the action of the intent to determine which of your methods to call:
if (intent.getAction().equals(CalendarService.ACTION_INITIALIZE_CALENDAR)) {
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
onInitializeCalendar(appWidgetIds);
} else if (intent.getAction().equals(CalendarService.ACTION_HIDE_GUIDE_OVERLAY)) {
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
onHideGuideOverlay(appWidgetId);
} else ...
Note: The code snippets are taken almost directly from my Glass Widgets, so to adapt it to your own use, you would have to replace the action constant with your own two actions (one action for each button), replace R.id.calendar_button_1 with the actual id of one of your buttons, replace the CalendarService with the name of your own service class and the methods onInitializeCalendar and onHideGuideOverlay with the name of the two methods in your service class that you want to call.
If you only ever have one instance of your widget visible at one time, then you don't need to fiddle around with the appWidgetId, but you probably can't guarantee that. I have some settings that can vary from widget instance to widget instance, so I put the id of the appwidget that was clicked into the intent, where the service can get at it when servicing my request.
I have a simple appwidget and I want to update it when an action occurs in an activity (in the same app). in onUpdate(), I immediately update the widget, which works fine. In my activity, I call the same static update method in my appwidget that is called in onUpdate() to update the views. the widget is not updated.
I can trace the code right into the AppWidgetManager.updateAppWidget() method, and all this good, but the widget does not update.
The only possible difference I can see is that the context object passed into my static update method is different, when it's called from the context of an activity vs. the context of a appwidget's onUpdate() method. however, there are lots of examples on the web of this so I expect it should work.
Without seeing your code I'm not 100% sure how you are trying to do it, however here is the method I use. Within my Activity I have the following method:
private void updateAllWidgets(){
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, MyWidget.class));
if (appWidgetIds.length > 0) {
new MyWidget().onUpdate(this, appWidgetManager, appWidgetIds);
}
}
Where MyWidget is the class of the appwidget. I can call this method from anywhere within my Activity to update all my appwidgets.
Rather than use a static method take advantage of the fact that the widget is already a broadcast receiver and register an update intent for it in your manifest. Then whenever you need to update it from the activity just call
//in your activity
sendBroadcast(new Intent(MyWidget.ACTION_UPDATE).putExtra(whatever));
//In widget class
public static final String ACTION_UPDATE = "com.example.UPDATE_MY_WIDGET";
and inside the receiver tags of your manifest file
<intent-filter>
<action android:name="com.example.UPDATE_MY_WIDGET"/>
</intent-filter>