I am updating the widget from service(srvice and widget class are in two different package) like this
AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
ComponentName widgetComponent = new ComponentName(this,MyWidgetProvider.class);
int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent);
Intent update = new Intent();
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);
update.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
sendBroadcast(update);
it updates my widget but the problem is that it also updating other widgets of the device too because of which my widget updates after all the widget gets updated.
So now I want to update only my widget how can i do that
According Android documentation getAppWidgetIds return a list of id that have been bound to specific WidgetProvider, that is all your widget instance id not id of widgets under other WidgetProvider.
Related
I developing small application widget and have some problem with updating of remote views. When widget updating through system call all is ok, but when I trying update widget from my service through this code:
AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
ComponentName widgetComponent = new ComponentName(this, NBRBAppWidget.class);
int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent);
Intent update = new Intent();
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);
update.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
sendBroadcast(update);
my widget view glitches. Example of glitch is on the video below
Video of RemoteView glitches
I checked that update views method took 7-20ms
If anybody has some assumption why this happening, please give me to know.
To avoid glitch of widget I just remove sending of ACTION_APPWIDGET_UPDATE broadcast and call RemoteView instead of it, like this:
AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
ComponentName widgetComponent = new ComponentName(this, NBRBAppWidget.class);
int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent);
for (int i = 0; i < widgetIds.length; i++) {
NBRBAppWidget.updateWidget(this, widgetManager, widgetIds[i]);
}
NBRBAppWidget.updateWidget is method that do calls to remote views
I am not going to delete this question as commons brings up some excellent points below, but I did rework the code and ask the question differently here: How do I retrieve shared preferences data in a Widget Service class without passing in incorrect default values or getting null pointer errors?
I am working on an app that takes a user's input choices and passes them to a widget. It is currently running a service to manage it and it works well, but I cannot figure out how to pass a String from one to the other effectively. Here is my code so far:
//First Widget config is called:
public class WidgetConfig extends Activity{
//Stuff happens here to get data from EditTexts and spinners and converts
//them to strings.
//Eventually a button is pressed which enters all the information:
public void onClick(View v) {
//I have already tried shared preferences like this:
//This was intended to give the shared preferences a unique identifier.
//It does not work for what I am trying to do
String str = Integer.toString(appWidgetId);
sp.putString(editor, str + "::" + "username", user_name);
//The appWidgetID was unique and so I thought it would work as an
//identifier for shared prefs.
//This is the intent for opening the provider
Intent intentUpdate = new Intent(context, MailWidgetProvider.class);
//I also attempted to put items here:
intentUpdate.putExtra("username", user_name);
//I left out the rest of the pending update code as it is irrelevant to this.
}
}
//Next the AppWidgetProvider is called
public class MailWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
ComponentName thisWidget = new ComponentName(context,
MailWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
//This is the intent to open up and run the service
Intent intent = new Intent(context.getApplicationContext(),
MailWidgetUpdateService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
context.startService(intent);
}
}
//Service Class
public class MailWidgetUpdateService extends Service {
public void onStart(Intent intent, int startId) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this
.getApplicationContext());
int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
ComponentName thisWidget = new ComponentName(getApplicationContext(),
MailWidgetProvider.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
//Loop through the IDs
for (int widgetId : allWidgetIds) {
int awid = widgetId;
String str = Integer.toString(widgetId);
String user_name = sp.getString(settings, str + "::" + "chosen_accout_string", "Loading...");
Log.d(TRACKING_USERNAME, user_name);
/*
Issue Here, see explanation below
*/
}
}
How do I retrieve the extras in the Widget Provider class from the widget config class and how do I go about passing them on to the service after receiving them?
You start by not doing much of any of that.
Your AppWidgetProvider is merely one means of updating the app widget contents, one that will specifically be used by Android when your app widget is added and on periodic updates as requested by your app widget metadata. Moreover, bear in mind that an instance of your AppWidgetProvider is used just once and is then discarded.
If you want to update your app widget in other places, go update the app widget, by creating the RemoteViews and giving them to an AppWidgetManager. Your AppWidgetProvider has nothing to do with it. To quote the documentation:
When an App Widget uses a configuration Activity, it is the responsibility of the Activity to update the App Widget when configuration is complete. You can do so by requesting an update directly from the AppWidgetManager.
If you want to have a common implementation of the update-the-app-widget logic, put that is some common class that is used by your configuration Activity, your AppWidgetProvider, and anything else that needs to update the app widget contents.
So, when the user configures the app widget through the activity, you need to:
update the app widget yourself via the AppWidgetManager, and
hold onto the configuration data (in a database, SharedPreferences, or other sort of file) so that it can be used for future updates
WHAT I NEED
I'm developing a custom Android launcher for a company, which will be installed on this company's tablets and therefore won't be published on any store.
It's basically a grid with widgets managed remotely (by a background service we're creating), which means that the app should decide which widgets to add or remove whenever the user opens it.
WHAT I HAVE
I'm using the following code to add the widgets:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getContext());
AppWidgetHost appWidgetHost = new AppWidgetHost(getContext(), APPWIDGET_HOST_ID);
appWidgetHost.startListening();
List<AppWidgetProviderInfo> appWidgetInfos appWidgetInfos = appWidgetManager.getInstalledProviders();
for(int j = 0; j < appWidgetInfos.size(); j++)
{
if (appWidgetInfos.get(j).provider.getPackageName().equals(widgetPackage))
{
// Allocates an id
int appWidgetId = appWidgetHost.allocateAppWidgetId();
// Gets the app widget info
AppWidgetProviderInfo appWidgetProviderInfo = appWidgetInfos.get(j);
// Creates Widget
AppWidgetHostView hostView = appWidgetHost.createView(getContext(), appWidgetId, appWidgetProviderInfo);
hostView.setAppWidget(appWidgetId, appWidgetProviderInfo);
// Insers the view to the layout grid
insertView(row, column, rowspan, columnspan, hostView);
//
break;
}
}
And it works just fine. The widget shows and it's buttons respond to user touch.
Here's one of the the widgets onUpdate:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
// Perform this loop procedure for each App Widget that belongs to this provider
for (int appWidgetId : appWidgetIds)
{
// Create an Intent to launch ExampleActivity
Intent launchAppIntent = new Intent(context, MapActivity.class);
PendingIntent launchApp = PendingIntent.getActivity(context, 0, launchAppIntent, 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.widget_layout);
views.setOnClickPendingIntent(R.id.widget_layout, launchApp);
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
THE PROBLEM
One of the widgets (shown above) calls an Intent to start it's fullscreen Activity when clicked, and this doesn't work on my custom launcher, though it works perfectly on the default home launcher.
Edit: I installed my app 4.x devices and there is no problem. Problem exists only with 3.x devices.
I am trying to update an AppWidget manually when a user setting
changes on the device. To do so I use code similar to this:
ComponentName thisWidget = new ComponentName(this, MyAppWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
I can tell that my AppWidget onUpdate method is being called as a
result since I log some debug strings to logcat in the code. However
the AppWidget itself doesn't change on the screen.
Here comes the interesting part: if I rotate my device and force a
refresh of the home screen (from PORTRAIT to LANDSCAPE or vice-versa)
then finally my AppWidget gets updated. However rotating the device
does not trigger the onUpdate method to be called, so the AppWidget
must be using the RemoteViews provided in the earlier update.
Can somebody explain me what to do to force the home screen redraw of
my AppWidget when it processes an update?
I am using <uses-sdk android:minSdkVersion="11" />
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context, MyProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
// Build the intent to call the service
Intent intent = new Intent(context.getApplicationContext(), MyService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.appwidget_layout);
appWidgetManager.updateAppWidget(appWidgetIds, views);
// Update the widgets via the service
context.startService(intent);
}
And my service:
#Override
public void onStart(Intent intent, int startId) {
Log.i(LOG, "Called");
this.appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext());
this.allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
ComponentName thisWidget = new ComponentName(getApplicationContext(), MyProvider.class);
int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget);
Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length));
Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length));
config = getResources().getConfiguration();
for (int widgetId : allWidgetIds) {
//do things like starting ASYNCs (couple of them) to fetch data from server
//and set an adapter for the gridview
}
Intent intentOpen = new Intent(getApplicationContext(), MainFragmentActivity.class);
PendingIntent open = PendingIntent.getActivity(getApplicationContext(), 0, intentOpen, 0);
remoteViews.setOnClickPendingIntent(R.id.widget_whole, open);
remoteViews.setViewVisibility(R.id.widgetProgress, View.GONE);
appWidgetManager.updateAppWidget( thisWidget, remoteViews );
Log.d(LOG, "sent!!");
}
stopSelf();
super.onStart(intent, startId); }
This sounds like a bug in the launcher app to me. Every time you call updateAppWidget the AppWidgetManager receives the new layout and the launcher is responsible for redrawing the widget with this new layout.
The fact that when the screen is rotated onUpdate and updateAppWidget are not called, but the launcher redraws the widget with its new layout means that the AppWidgetManager has already successfully received that new layout.
When the screen is rotated the launcher is forced to redraw everything (its Activity is recreated) and that is why it shows the new layout.
And this bug is probably fixed in Android 4.0+
I would try calling invalidate() on the Views in your widget. Calling that forces the system to redraw the View.
I read some example in internet/book about the App Widget, a normal example to update the widget is in onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) method of AppWidgetProvider like this:
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.mywidget_layout);
updateViews.setTextViewText(R.id.mytext, "updated text");
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
}
It update each Widgets in a loop.
But now, I have to implement an App Widget, it is updated in BroadcastReceiver, onReceive(Context context, Intent intent) method since there are no int[] appWidgetIds passed in. So I implemented the code like this:
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.mywidget_layout);
updateViews.setTextViewText(R.id.mytext, "updated text");
ComponentName myComponentName = new ComponentName(context, AndroidBatteryWidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(context);
manager.updateAppWidget(myComponentName, updateViews);
It didn't update widget one-by-one, but actually all widgets were updated at once. Even though it worked as I want, but I got confused as to why there is no need to update all widgets one-by-one as before.
What's the difference between two methods?
Can I send another broadcast from BroadcastReceiver.onReceive() to trigger AppWidgetProvider.onUpdate()? And how to?
It's the same thing. Update with ComponentName loops through all the ids like your first code block.
You can see it in the Android code here:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.4_r1.2/com/android/server/AppWidgetService.java#AppWidgetService.updateAppWidgetProvider%28android.content.ComponentName%2Candroid.widget.RemoteViews%29