I am developing an appwidget that uses the RemoteViews to display a ListView. For simplicity's sake, I will give an analogy of the appwidget's functionality:
The user will select to add the appwidget to the home screen. Upon selecting the widget, a configuration activity is launched and the user selects from one recipe from a list of recipes.
Upon selecting the recipe from the configuration activity, the configuration activity broadcasts the AppWidgetManager.ACTION_APPWIDGET_UPDATE intent. This intent received and handled in the onReceive method of my AppWidgetProvider class. From here the RemoteView is instantiated and passed into the AppWidgetManager.updateAppWidget() method. This proceeds to fill in the ListView of ingredients.
This all works as expected, except when I attempt to manually update the ListView from the appwidget. I have set a PendingIntent to re-launch the configuration activity, which also works. Unfortunately, the call to AppWidgetManager.updateAppWidget() does not get called instantly as it did when being launched upon adding it to the home screen and the ListView does not get updated. The update does get called, however, after scrolling down the list a ways (until it gets passed the number of rows it has loaded in its cache, I reckon). This fires off my FlightBoardAppWidgetService and ViewsFactory as it should. It is almost as if the updateAppWidget is getting put into some lazily-loaded queue. I tried to look at the Android source code to see how AppWidgetManager.updateAppWidget() is coded, but it appears to be hidden.
tl;dr: AppWidgetManager.updateAppWidget() does not always get called instantly, what gives?
Is there any way to get the ListView to update when it is actually called? What am I doing wrong? Thanks!
Well, I ended up solving the problem finally. It is somewhat of a hack, but I ended up solving the problem by declaring a refresh broadcast and an update broadcast. Each time I want to update the widget I call updateAppWidget(), and then from the function that receives and handles this broadcast, I launch another broadcast that calls notifyChanged. This works all of the time!
Related
I'm currently developing a widget that requires the user to be logged in. When the user initially adds the widget and they're not logged in, I take them to the login activity so that they can log in. However, I don't want to do that when the widget auto-updates (it would be very annoying to have an app randomly launch when you're just browsing your home screen).
The updating code is currently in onUpdate(), but I haven't been able to figure out how to differentiate between the update that occurs when the widget is initially added and the update that occurs periodically. Is there a way to do this?
To summarize, I'm trying to make the following:
- Initial update when user adds the widget: Open login activity
- Subsequent periodic updates: Don't open login activity
Note: I'd like to avoid onEnabled(), since that is only called when the FIRST widget is added. I'd like my code to run every time a new widget is added.
If you are looking for just one instance of your widget, then you could go with shared preference boolean to solve this issue.
onEnabled - Clear boolean
onUpdate - if boolean not set -> Means first time (Do your work and set the boolean)
If boolean is set -> Means its the normal widget update.
Work around option if you need to deal with multiple widget instances :
If you need to achieve the above requirement, you need to handle auto update in intervals by your own.
That means, all the the call towards onUpdate should come from your own created Intents. That is :
Use Alarm manager to trigger the onUpdate functionality of Widget. Add bundle value to intent stating its an update call.
All widget interaction intents should contain the bundle value to say its an update call.
In onUpdate method, check for the same bundle value mentioned above and if its there, its a normal update else BINGO... :)
The problem is only when my activity already shown it begins updates and it look no good. How it works: in onStart of activity I send cmd to service to get update data, also I register brodcast listener there. I want to prepare received data from service to show before activity appears. How to do that? Thanks.
How it works now: when I back from another activity first I see old data and then it changes (very fast but you can see it) to new.
if you want to setup things before your activity is shown you need to do things in the onCreate method instead of onStart method.
further informations in android documentation
When you send the command to the service to update your data, you should change the views in your Activity to show loading indicators, or a blank view, or whatever you want the user to see until the Broadcast comes in that your new data is ready. Then you shouldn't need to worry about old data being visible.
I am a newbie in Android development and I am faced with a problem which I can't figure out. I am following this link. It is a simple widget which has a listView which shows harcoded feed.
I wanted to make the widget interactive. So I came up with a solution as follows: I created a Intent, associated with it a Action and Broadcasted it with PendingIntent. Now I tried to catch that Intent in the onReceive() function of the WidgetProvider.java class.
I thought this approach is great except the fact that onUpdate function is called every 30 minutes. I am not sure even if it works after 30 minutes, haven't tried it. So I can't figure out how do I achieve this.
Basically I wanted to make it into widget, on which if clicked, it launches another activity. And can you also tell when is the onReceive function of the AppWidgetProvider called.
I have an android app widget that gets some information from the internet when it is first launched.
More precisely it launches a service that asynchronously does a network call. At the end of that network call, in the UI thread it updates the remoteview for the widget with new information.
Touching particular parts of the widget loads an activity which does check to see if the network call stored anything, but that is a conditional statement based on the size of the network call response, if that object doesn't contain the right things then it won't load that.
My problem is that touching the widget doesn't seem to load the activity UNTIL the asynchronous network call finishes. And this doesn't make since to me because that is a separate thread.
There never seems to be a circumstance where my activity gets to even check the condition for an empty object. Instead, I touch the widget, and that seems to be put into a queue, so when the network call finishes it then loads my activity and displays information about that network call.
Why is this happening? Is it something about how I update my remoteView? My views have listeners on them from when they are first placed on the launcher screen in the onUpdate method of the widget. Thanks
whenever I recreate the home screen widget on my phone, the onReceive() method is not called.
the problem would be that it doesn't respond to Button press that I assign which its function resides in the onReceive method..
The issue does not reside on the emulator but when I tested it with my phone, it doesnt respond to it.
What would be the best solution for it?
Since you don't have any more detail stuff (maybe some source code on how you register the receiver and how you bind the pending intent). Probably your phone is a model with sliding keypad, or those home screen can change orientation. Because when screen orientation of home screen changed (or any hardware configuration), the home screen is inflated and recreated. So, for your buttons, the intent that originally bound to it is gone after the recreation. According to the documentation (sorry, can't find the link), the inflater will only get the latest update from remoteviews. So, the following would not work:
RemoteViews rv = ...;
// Assign the button to some pending intent
rv.setOnClickPendingIntent(View, pi);
AppWidgetManager.Update(...);
// And after sometime, you make changes to the rv
rv.setFloat();
// And update again
AppWidgetManager.Update(...);
It is still ok and the button will fire the Pending Intent as expected, but, if for any reason configuration changed and the home screen is invalidated (and recreated), the appwidgetmanager will only update according to the last update, which, did not specify anything about the clicking intent.
Solution to this is, everytime you update the remote view, you have to set all the pending intent as well. I am not sure how it would impacts the performance, but it is the only working method I can have. (but my widget is updating like 16 times/second and at least it works :)