Android app widget wont update - android

I have simple widget for showing forecast and I am trying to update it after my request to the API I use is done. But I get this freaky error : "E/Finsky: [1] com.google.android.finsky.widget.a.onReceive(146): Refusing to update all widgets; need to narrow scope"
private void updateWidgets(Context context){
Intent updateIntent = new Intent();
updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
context.sendBroadcast(updateIntent);
}
I have tried to call this method in the activity, in the end of the service, or in a broadcast receiver(listening for broadcast from the service after its finished). Could anyone give me a suggestion what could I do wrong?
Widget class:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for(int i = 0; i<appWidgetIds.length; i++){
int currentWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.weathy_widget_info);
//Some other unrelated stuff
appWidgetManager.updateAppWidget(currentWidgetId,views);
}
}
The method triggers the update, but it wont update the widget, and I dont know what is the problem. Also will it be possible to be something with working with SQLite in the onUpdate()?

Related

How to cancel creation of android home screen widget

I have a widget for my app. On widget Creation when android triggers onEnabled I'm checking if a user meets a certain requirement then the user can go ahead and create a widget. But I need to stop widget creation if they don't meet a certain requirement. I can't figure out how to cancel widget creation dynamically. Here's what I was trying which didn't work.
RemoteViews views;
void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
// Construct the RemoteViews object
views = new RemoteViews(context.getPackageName(), R.layout.lock_widget);
views.setOnClickPendingIntent(R.id.lock_widget, getPendingSelfIntent(context, LOCK));
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
// Query User pro status when creating widget
Log.d("Widget", "OnEnabled Fired");
views.removeAllViews(views.getLayoutId());
//views.
}
views.removeAllViews(views.getLayoutId()); doesn't seem to work.
Is there even a way to this. The workaround that I'm using is checking certain requirement check in onUpdate.
The best solution in your case, enable widget component, if user have all "certain requirement".
So i assume a following case. User uses your app, and in some cases (you enable widget component, if user lose his "certain requirement" just disable widget component, so there is no widget in widget picker). You can easily achieve this through PackageManager.
Updated: When user have a pro status, just enable widget, if not - just disable
public static void setComponentState(Context context, boolean enabled) {
int flag = (enabled ?
PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component = new ComponentName(context, YourAppWidgetProvider.class); // or make component via package name and class name (check Component constructors)
PackageManager pm = context.getApplicationContext().getPackageManager();
pm.setComponentEnabledSetting(component, flag, PackageManager.DONT_KILL_APP);
}

How do I pass data from a widget config class to a widget provider class via intents?

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

Android working with views in widget

I am trying to make a widget for my app, and I want it to be with a buttonm progress bar and text view, which would later be changed, so I need to somehow work with the views themselves, like I can from an activity, show a view, hide a view, change a button background etc...
I tried tweaking with the sample code from the Android documentations, but I can only start an activity with this
public class WidgetProvider extends AppWidgetProvider {
#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];
Intent intent = new Intent(context, ActivityMain.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
}
Does the widget need to be connected to an activity in order to make actions (connect to the internet, write in the database, write in the objects of the apps instance (if there is one))? And can I work with views the way I am asking?
Outside of setting on-click PendingIntents on views, there isn't much you can do inside of a widget. The standard recipe is:
Make a PendingIntent that sends a broadcast (PendingIntent.getBroadcast()) and set it on the appropriate view in your widget.
In the BroadcastReceiver that receives the intent, you update the widget to show a spinner and start a Service to do whatever long-running work you want to do (e.g connect to the internet).
Once that work is done, you can update your widget again and remove the spinner.

Getting data from Android app to widget and displaying it

I have started implementing a widget into an application of mine and I am having some trouble getting the data from the application to the widget.
Here is the code for my widget:
public class ElectricityMonitorWidgetProvider extends AppWidgetProvider {
public static final String WIDGETTAG = "WidgetMood";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
System.out.println("Widget onUpdate called..");
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];
System.out.println("In loop. App widget id: "+appWidgetId);
}
}
}
In my widget I have only a textview that I want updated with a number from my application. The application gets this number via a web request.
In the onUpdate() method which runs periodically I want to be able to update that one textview.
I am not sure how to achieve this.
Do I need to implement a helper class that the widget calls and inside that helper class I have the same method as the application uses to receive the data it uses or?
This is my first time implementing a widget. I have read through the guide on widgets on developer.android.com and that helped me get the widget to show on my phone. The only thing I am missing is the functionality that I describe.
Thanks for any help.
put this in your widget updating loop
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
int value = i; //replace with actual value eg from SharedPreferences
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.your_widget);
remoteViews.setTextViewText(R.id.text_view, String.valueOf(value)); //assumed that R.layout.your_widget contains a TextView with R.id_text_view id
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
System.out.println("In loop. App widget id: "+appWidgetId);
}
Please note, that this code does not specify any action upon user touching the widget (generally you need to specify a PendingIntent and hook it with RemoteViews.setOnClickPendingIntent method).
Also, I would suggest that you update your widget when needed and not periodically e.g. your app could send custom Intent to your AppWidgetProvider, which would handle it in overridden onReceive() and update RemoteViews on widgets.

Long-running operation to update an Android appwidget

I have a widget that needs to perform a potentially long-running operation in onUpdate(). Just performing the operation directly resulted in ANR's. To solve this, my first attempt was to create a thread therein. I noticed that the widget would not get updated in some cases. My guess here is that once onUpdate() exits, Android may kill the process along with the unfinished thread.
My next attempt was to create an intent service. The widget's onUpdate() just starts the intent service, which does the work directly and updates the widget when done. This works, but much to my surprise it appears that onHandleIntent() is single-threaded. If I have two widgets, and then both update and start the intent service, they update sequentially ...
The two widgets case is not really important, but I'm just wondering about a best practice for this type of pattern.
To solve the two widgets case I ended up updating all the widget instances with the same data whenever any one of them is clicked. e.g., I perform the long-running process once and apply the results to all the widget instances. In my scenario this doesn't matter, but for many widgets, it might be important not to do that.
Thoughts?
but much to my surprise it appears that onHandleIntent() is single threaded
Yes.
if i have two widgets, and then both update and start the intent service, they update sequentially ...
Yes.
but i'm just wondering about a best practice for this type of pattern.
Your IntentService was a fine upstanding solution, IMHO. Remember that Android runs on slow CPUs, with devices with little RAM. Running lots of threads in parallel is generally not a good idea.
then i'm getting into starting a thread in onHandleIntent(), which requires a wake lock, and it just seems it's getting all too complicated.
Try my WakefulIntentService.
make onUpdate call your own function to cycle through the widgets and update them. Do your async task before the cycle. You will want two separate actions, one that asks for the update to start, and one that your IntentService will broadcast to let the widgets know they are finished. Hope this helps.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
updateWidget(context, appWidgetManager, appWidgetIds);
}
private void updateWidget(Context context){
ComponentName widget = new ComponentName(context, MyWidget.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(widget);
updateWidget(context, appWidgetManager, appWidgetIds);
}
private void updateWidget(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final boolean isEnabled = true; //took out code didn't want you to see
// start intent service here
for(int i = 0; i< appWidgetIds.length; i++){
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(isEnabled ? ACTION_TOGGLE_OFF : ACTION_TOGGLE_ON);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.widget , pi);
views.setImageViewResource(R.id.widget_image, isEnabled? R.drawable.widget_on : R.drawable.widget_off);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}

Categories

Resources