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.
Related
Is there any work around to call an activity directly from a button on a widget? Like a beautiful button to launch the app.
From the doc and some answers here, views.setOnClickPendingIntent is the only way and that requires a service. But I don't need a service cause I'm not really updating the widget!
Actually, my original task is quite simple. I want an icon on home screen that calls an activity, but I don't want that icon appears in app-drawer. I know I can put a lot of activity icons in app-drawer.
You dont need a service for that.
You should just setOnClickPendingIntent in the onUpdate method in your AppWidgetProvider.
here are some links that show how it can be done, they are basically the same with some variations, you should try them out:
Start activity by clicking on widget
Launching activity from widget
How do I run an Activity from a button on a widget in Android?
How Do I Launch an Activity with Home Widget
Like i said there is no need for a service.
here is the sample code i used:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
RemoteViews remoteViews=new RemoteViews(context.getPackageName(), R.layout.testwidget);
//Intent set with the activity you want to start
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.textView1, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
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'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()));
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.