android appwidget won't update from activity - android

I have a simple appwidget and I want to update it when an action occurs in an activity (in the same app). in onUpdate(), I immediately update the widget, which works fine. In my activity, I call the same static update method in my appwidget that is called in onUpdate() to update the views. the widget is not updated.
I can trace the code right into the AppWidgetManager.updateAppWidget() method, and all this good, but the widget does not update.
The only possible difference I can see is that the context object passed into my static update method is different, when it's called from the context of an activity vs. the context of a appwidget's onUpdate() method. however, there are lots of examples on the web of this so I expect it should work.

Without seeing your code I'm not 100% sure how you are trying to do it, however here is the method I use. Within my Activity I have the following method:
private void updateAllWidgets(){
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, MyWidget.class));
if (appWidgetIds.length > 0) {
new MyWidget().onUpdate(this, appWidgetManager, appWidgetIds);
}
}
Where MyWidget is the class of the appwidget. I can call this method from anywhere within my Activity to update all my appwidgets.

Rather than use a static method take advantage of the fact that the widget is already a broadcast receiver and register an update intent for it in your manifest. Then whenever you need to update it from the activity just call
//in your activity
sendBroadcast(new Intent(MyWidget.ACTION_UPDATE).putExtra(whatever));
//In widget class
public static final String ACTION_UPDATE = "com.example.UPDATE_MY_WIDGET";
and inside the receiver tags of your manifest file
<intent-filter>
<action android:name="com.example.UPDATE_MY_WIDGET"/>
</intent-filter>

Related

Widget does not works after “Clear Memory”

The problem is that after I use the built in Task Manager's Clean Memory/Ram, My widget stops working .I guess this is related to the Task Manager's method of cleaning RAM.After a lot of research and some attempts, I found that i need
BroadcastReciever to listen to package changes and updates:
So i implemented but its not working because document says that the Restarted/Cleared package does not receive this broadcast
register receiver in the manifest file:
<receiver android:name="com.app.lab.receiver.onRestartReciever">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
<data android:scheme="package" />
</intent-filter>
PACKAGE_REPLACED - called in particular to notify application update.
PACKAGE_RESTARTED - called when most memory cleaners are cleaning memmory.
the "data" row is used to monitor action applied for the specific package.
public class onRestartReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d("DEBUG", "onRestartReciever");//I am not getting this log on clearing memory from task manager
}
}
I tried to use dummy service to get its lifecycle ie to check when onDestroy is called but what I found it not a reliable way ,onDestroy may not be called when application is killed by Task Manager.
So finally, my question : Is there any way to tell the android system to reStart appWidgets when Task manager or OS cleans memory .
Note: My widget contains only one button that launches an Activity.It works most of the time but stops responding if OS itself cleans memory or user forcefully do it from task manager.I've downloaded some of the widget it seem to continue working fine after cleaning memory also.
Update: To under my problem no need of going through complete code it is simple Application . My application dose not contain any Activty or Service. It contains only widget with one button which gives toast message.There is only two class in my application(WidgetProvider and onRestartReciever) thats it
Widget class WidgetProvider.class
public class WidgetProvider extends AppWidgetProvider {
private RemoteViews remoteViews;
private ComponentName watchWidget;
PendingIntent pi;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.touchwidget);
Intent toggleClickPlayer = new Intent(context.getApplicationContext() ,WidgetProvider.class);
toggleClickPlayer.setAction("PLAYER");
PendingIntent toggleIntentPlayer = PendingIntent.getBroadcast(context,0, toggleClickPlayer,endingIntent.FLAG_CANCEL_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.player, toggleIntentPlayer);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
watchWidget = new ComponentName(context,WidgetProvider.class);
remoteViews = new RemoteViews(context.getPackageName(),R.layout.touchwidget);
Toast.makeText(context, " Player started",Toast.LENGTH_SHORT).show();
(AppWidgetManager.getInstance(context)).updateAppWidget(watchWidget, remoteViews);
}
}
}
Widget does not bound to application life cycle. All the widgets are bound together. If all what your widget got is a button than there is no reason for it to stop working. You problem is some place else.
For some reason your button intent is fail to start what you set it to start.
If you show me your code for setting the button, I be able to help you more, but it is another question, and you better Google for answer before posting.
EDIT: It looks like you didn't understood the idea of widgets. Right now what your button is doing is starting the widget. It looks weird to me, I am not sure what exactly is happening there... I suggest that your button will start a completely new service. That service will show your toast. You defiantly do not need to listen for restart package broadcast.

Android widget not responding to touches

I'm trying just some very simple code to get an Android widget going but with no luck. I've looked around everywhere and haven't found a good answer.
All I want (for now) is to increment a counter when the widget is touched and display the current value.
This is my AppWidgetProvider:
public class WordWidget extends AppWidgetProvider
{
Integer touchCounter = 0;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
//This is run when a new widget is added or when the update period expires.
Log.v("wotd", "Updating " + appWidgetIds.length + " widgets");
for(int x = 0; x < appWidgetIds.length; x++)
{
Integer thisWidgetId = appWidgetIds[x];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());
Intent widgetIntent = new Intent(context, WordWidget.class);
widgetIntent.setAction("UPDATE_NUMBER");
PendingIntent widgetPendingIntent = PendingIntent.getBroadcast(context, 0, widgetIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widgetLinearLayout, widgetPendingIntent);
appWidgetManager.updateAppWidget(thisWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent)
{
Log.v("wotd", "In onReceive with intent=" + intent.toString());
if (intent.getAction().equals("UPDATE_NUMBER"))
{
Log.v("wotd", "In UPDATE_NUMBER");
touchCounter++;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());
} else
{
Log.v("wotd", "In ELSE... going on to super.onReceive()");
super.onReceive(context, intent);
}
}
}
This is part of my manifest:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<receiver
android:icon="#drawable/ic_launcher"
android:name="com.example.mywidget.WordWidget"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="UPDATE_NUMBER" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widgetinfo" />
</receiver>
</application>
The log shows the onReceive() is called immediately after being placed on the home screen, and after being touched, however the number never increases. I don't totally understand how widgets work, but are they killed after onUpdate()? So to do this I would have to use some kind of persistant storage?
Also, if I currently add another widget both would show the same values and increment even if I just touch one. Is there a way for each and any widget to have it's own counter?
Thanks!
Actually you have answered your question. But let's clarify some things:
A. AppWidgets are NOT killed as long as they are on a home screen. But they don't belong to you. They are running in the process of the home application. To be more specific their views are running in the process of the home application, this is why you are see your widget but it doesn't do what you are expected and this is why we are using RemoteViews instead of Views in order to update them.
B. AppWidgetProviders (in your case the WordWidget class), on the other hand, are destroyed as soon as the onReceive method finishes. All the variables in them are re-initialized every time the onReceive method gets called. This is why your number never increases. The purpose of an AppWidgetProvider is to update the widget's RemoteViews and to inform your application that a registered broadcast has arrived.
C. AppWidgetProvider's onUpdate method provides you an Array with the widgets Ids that must be updated. This is the only code point you can use to get the number of your widget instances and their Ids. Because of the RemoteViews there is NO way to get some useful value from the Views of your widget (for example you can NOT read the counter value from the TextView) so you must use the provided information and DO persist your counter values per widget id. When the next onUpdate gets called you read the value from the storage, increase it, update the widget with the new value and then store the new value back.
D. If your widget has to do many things or slow things (like networking) when its time to update itself, you should consider using a service for this. But in your case (to increase a number) your approach is just fine as long as you persist the counters in the persistent storage or somewhere else.
Finally I 've noticed that in your onReceive override you are calling the "super.onReceive" only if you don't receive the "UPDATE_NUMBER" action. This is NOT a good practice, unless there is a GOOD reason (that's another story) always call super.onReceive as the first or the last command in your override.
Hope this helps...

Widget not updating when Activity content changes in Android

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

Update a widget from a service

I'm trying to update a widget from a service... the service start a thread that execute this code
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(Worker.this);
RemoteViews remoteViews = new RemoteViews(Worker.this.getPackageName(), R.layout.mywidget);
ComponentName projectWidget = new ComponentName(Worker.this, MyWidget.class);
remoteViews.setTextViewText(R.id.widgetstate, "update");
appWidgetManager.updateAppWidget(projectWidget, remoteViews);
the onUpdate method just print a log, but this log is printed only when I create the widget, not everytime the thread cycles... where I'm wrong?
Thanks in advance
You're not wrong. You just update the widget without calling onUpdate(). It's just a convinience method that gets called in response to the ACTION_APPWIDGET_UPDATE broadcast by the system. You don't have to call it to update a widget, it also just works like you did here. ¹
To invoke it you can send the broadcast or call it by hand though, it's a good idea to keep the widget update functionality in one place from a code structure point of view to find things easily.
¹ Take a look at the AppWidgetProvider source, line 56. The whole AppWidgetProvider is just a BroadcastReceiver that does some work for you already - and it does start the update in the same way.

Call widget's onUpdate method from the app's main activity

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()));

Categories

Resources