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... :)
Related
I have a screen listening for a data class that contains everything I need. ScreenState. Whenever the user press a button I send the event to a ViewModel. This specific event is just getting the intent and setting on the ScreenState parameter like this.
screenStateFlow.emit(
ScreenState(
Intent(...)
)
)
What happens there is, first time works (User leaves the app and then comeback to the app). When user comebacks to app and there's not any data from the intent and want them to be able to start an intent again. So it does the same action.
Triggers a specific event which gets the intent and sets on the ScreenState parameter and this value is emited, again
And here lays the problem. Value is the same. So compose doesn't recompose itself.
And this solution works. You could say that I don't need all of this and it could work by just starting the intent without having to go through the event process and etc.. But I want it that way (unless I don't find a proper solution)
screenStateFlow.emit(
ScreenState(
Intent(...),
!triggerRecompose
)
)
Is there any better solution?
Edit: Someone having the same issue as me, the provided answer didn't work. I've already tried the MutableState and the State from compose in ViewModel. Didn't work
I had a similar issue in which I wanted to trigger a snackbar even if the value is repeated.
I solved it by adding a variable parameter to my message object (such as timestamp or Math.random()).
In this way, even if the message content is the same, the Message object is different and it triggers a state change.
I want to create a widget for my android app that display some real time details about locations e.g. weather. but i want to allow max 3 instances of the widget at any point of time, each with a different location. I am not sure how to go about it and can't find any information.
my questions are:
Is there a limit on number of appWidget instances that could be created?
How to go about limiting the number of widget instances user can create at any point?
there are multiple ways to count the app widgets that i can think of:
send an intent to all of your app widgets to see that they still exist, and count them, and only in the end you would know how many there are. however, i'm not sure how you would know when to stop counting.
not sure if it works but maybe you could use:
final ComponentName cn=new ComponentName(context,YourAppWidgetProviderClass.class);
int[] appWidgetsIds=appWidgetManager.getAppWidgetIds(cn);
and check the size of the result.
update the counter based on receving the ACTION_APPWIDGET_DELETED (or ACTION_APPWIDGET_DISABLED) and ACTION_APPWIDGET_BIND (or ACTION_APPWIDGET_ENABLED) actions in the intents on the onReceive() method of your AppWidgetProvider class.
anyway, if there are too many (4 or more in your case) , just show an alternative layout for the new widget.
you would also need to handle the case of removing app widgets (those that weren't disabled) so that you would enable new ones (and decrease the counter), or you could let the user click on disabled ones to trigger the check again.
about limiting the creation itself, i don't think it's possible, but as i wrote, it's possible to count them and disable new ones.
do note that the user might have the app widget available on more than one app . it doesn't even have to be a launcher that will show your app widget. also not sure how it would work in case there are multiple users (available on android 4.2 and above) .
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!
I am trying to debug a problem where my widget becomes invalid and a new one fills in. This only happens once at the beginning of time and then it remains the second widget forever. So, I want to put code in to narrow down the point in time when it happens. What I would like to do it something like this:
e.g., (not real code) Log.d(TAG, "myWidgetId=" + this.getMyWidgetId());
Then I would get a list of all the enabled IDs and see if I am in the list. I cannot find a method, member, attribute, etc. that would give me my id?
It cannot be done. The AppWidgetProvider's ID is implicitly handled and can change, therefore, the best one can do is to ask the AppWidgetManager to generate a list of the widgets for a particular component, invoke them, then respond to the service request using the provided ID.
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 :)