I have been working with this problem for three days now and I've looked at every single question on here for an answer. I have a widget with a button on it and all I would like it to do is start a service everytime it is clicked. The problem is that the button stops working randomly. I can't recreate it at all and I have no idea what causes it. My service calls stopSelf(); but I have had this problem with a broadcast receiver also so I believe the problem to be in the widget and not in the service. Here is the code
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Log.i("Widget", "onUpdate");
final int N = appWidgetIds.length;
for (int i=0; i<N; i++)
{
int appWidgetId = appWidgetIds[i];
Log.i("Widget", "onUpdateLoop");
Intent intent = new Intent(context, ServiceWidgetAction.class);
intent.setAction(Long.toString(System.currentTimeMillis()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent
.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget);
views.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);
views.setTextViewText(
R.id.widgetTextView,
"Some text");
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
I've checked this code over and over and I have no idea why it is doing this. It does this on 3 separate phones and I can't recreate it. I've tried force stopping the app, clearing it from a task manager adding new widgets etc. to get the widget to stop working and it won't. However when I woke up this morning the widget no longer works. Any help would be GREATLY appreciated.
I ended up figuring out the problem. I was updating the widget from other places in the app and I did not have the complete code for each one. In other words my app updated the textviews in the widget like this
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget);
views.setTextViewText(
R.id.widgetTextView,
"Some text");
appWidgetManager.updateAppWidget(appWidgetId, views);
But it needed the entire code to keep the button registered like this:
Intent intent = new Intent(context, ServiceWidgetAction.class);
intent.setAction(Long.toString(System.currentTimeMillis()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent
.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget);
views.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);
views.setTextViewText(
R.id.widgetTextView,
"Some text");
appWidgetManager.updateAppWidget(appWidgetId, views);
So bottom line is whenever you update a widget from within your app, make sure it looks exactly like the code in the widget itself. Don't leave anything out.
Did you install your widget into the SD Card?
Google recommends to install all widget, alarm and receiver app types into the internal storage, due system sync problems like this.
Maybe not the solution, but a "must check" ;)
android:installLocation="internalOnly"
Related
How can i go to my App when i click on AppWidget
I saw no. of questions how to create widget in android home,but after craeting widget how to go to my app while clicking on that i didn't get from anyone of that.Please give me the guidelines to achieve this.
Thanks,
Since it is an AppWidget setting an onClickListener won't work. Instead you have to set an onClickPendingIntent on a specific view.
See the following code for the necessary steps (you should put this code into your onUpdate() method):
// Inflate the Widget layout
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.your_widget_layout);
// Create and set the Intent
Intent intent = new Intent(context, MyClass.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, appWidgetId, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
// Add intent to a view (like a button)
remoteViews.setOnClickPendingIntent(R.id.your_button, pendingIntent);
Please note: The code only shows the relevant parts
As greenapps say :
Add a listener in your widged's view (e.g : click)
Create an intent and put extra information (e.g witch item is clicked)
Then start your activity.
e.g
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
//...
Intent intent = new Intent(context, YourActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.widget_layout, pendingIntent);
//...
}
}
I want to combine my widget and one of my android application..
Is it possible to do that?
My plan is, once user open up my android widget, the widget will directly open up my android application?
Is there any way how?
I made some method here from my widget class:
public class ExampleAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = startActivity(new Intent("com.xxx.yyy.widget.FlamingoActivity"));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget1);
views.setOnClickPendingIntent(R.id.Image, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
I tried to call the second app, FlamingoActivity, but its failing.. :(
NOT THE FULL SOLUTION:
I should change this line
Intent intent = startActivity(new Intent("com.xxx.yyy.widget.FlamingoActivity"));
to this:
Intent intent = new Intent(context, FlamingoActivity.class);
You need to set an onClickpendingIntent on your widget
Intent intent = new Intent(context, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 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.appwidget_provider_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
And also See this question Launching activity from widget
The activity that you are trying to call needs to be public (exported) in the manifest of its app. There is nothing special about starting activities from a widget, other than the fact that you use a PendingIntent to allow the widget to work as a part of your app (it runs inside the launcher app).
I'm making a widget in android which produces a random number when clicked. When the widget is alone on the home screen it works perfectly, however when you add multiple of them they start to generate random numbers at the same time. Whats happening is when an individual widget is clicked it updates all of them; resulting in many random numbers. What i want is each widget to be isolated from the others; basically when a widget is clicked it only updates itself and non of the others around it. I think this is achievable by getting the ID of the current widget and update that one only, as apposed to the update method updating all the widgets; how do i do this?
My code
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context,
MyWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds) {
// Create some random data
int number = (new Random().nextInt(100));
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
Log.w("WidgetExample", String.valueOf(number));
// Set the text
remoteViews.setTextViewText(R.id.update, String.valueOf(number));
// Register an onClickListener
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
Summary:
This code is the update method and is called when a widget is clicked. I want this method to only update the widget ID that called it, not for this method to update all the widgets ID's on the home screen.
I had the same problem and I found this way to solve it:
1.To be able to distinguish between multiple instances of the same AppWidgetProvider, when registering the “onClick” event (intent) you must add an extra value with the widget ID (appWidgetId):
Intent clickIntent = new Intent(context, DigiStation.class);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, clickIntent, 0);
2.Update only the views of the current instance:
appWidgetManager.updateAppWidget(appWidgetId, views);
3.Android reuses intents, so when you create an intent, make sure you put an unique ID, or else the same intent used before will be triggered for all instances:
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, clickIntent, 0);
4.When handling the click event, get the appWidgetId from the “extras” payload of the intent.
You can found more useful details here.
I have implemented a App Widget to launch my activity when clicked.
onUpdate() method of WidgetProvider:
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];
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.mywidgetprovider_layout);
// ....update updateViews here
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
Intent onClickedIntent = new Intent(context,MyActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, onClickedIntent, 0);
updateViews.setOnClickPendingIntent(R.id.myView, pi);
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
}
}
It work as expected after the widget added on home screen.
But after sometimes, it cannot launch the activity again! I have to remove the widget and add again.
How can I fix it? please help.
I'd do it like this:
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.mywidgetprovider_layout);
Intent onClickedIntent = new Intent(context,MyActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, onClickedIntent, 0);
updateViews.setOnClickPendingIntent(R.id.myView, pi);
for (int i=0; i<appWidgetIds.length; i++) {
appWidgetManager.updateAppWidget(appWidgetIds[i], updateViews);
}
}
One thing I'm not sure on is the call to super.onUpdate(). My own widget code doesn't have it and seems to work fine... not sure if it's needed or not.
I don't know if this refactor will fix your issue though!
I know this is like two years late but I struggled with this too until today when I think I know what I was doing wrong. I think the main key is to focus on the use of the RemoteViews class. You prepare these objects as a sort of instruction set for a another process to follow. Setting the "on click pending intent" must done before sending it to the updateAppWidget method, so your first call to that method won't prime your "myView" object for clicks. Your code next sets the onClick trigger and calls updateAppWidget a second time. It looks like that one should work but there is a whole confusing subject regarding just when two intents are distinct or ambiguous which you may want to read about to understand why your code is working unpredictably. If I'm right, the take-away is to simply not call updateAppWidget the first time and then always make sure to set your onClick trigger whenever creating RemoteViews objects. I hope so anyway.
I have a widget, its setup so that when I click on it, it opens some settings in an activity.
views.setOnClickPendingIntent(R.id.btnActivate, pendingIntent);
This configures some settings for the application. What I want to achieve is to have the widget update its view to reflect the changed settings when the Activity I launch closes. Using the update interval or any other type of polling isn't appropriate for this.
I've seen a couple places here and in the android docs this code used:
appWidgetManager.updateAppWidget(mAppWidgetId, views);
But I don't know how to get the mAppWidgetId value. I tried following the example for a widget configuration activity here http://developer.android.com/guide/topics/appwidgets/index.html, but in the following code,
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
extras is always null, so I never get the AppWidgetID.
Ok, now I'm just rambling. What do you think I can do?
I finally found the answer I was looking for, it was in an overload of the updateAppWidget function.
appWidgetManager.updateAppWidget(new ComponentName(this.getPackageName(), Widget.class.getName()), views);
This let me access the widget without having to know the appWidgetID. My final code in my activity is then:
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(this, Settings.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
views.setOnClickPendingIntent(R.id.btnActivate, pendingIntent);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetManager.updateAppWidget(new ComponentName(this.getPackageName(), Widget.class.getName()), views);
finish();
I have to do all the same setup stuff I had to do in the onUpdate method of the Widget, but now every time I exit my activity the Widget is displaying the correct state.
There's another way to do it - pass the widget id in the pending intent that you use to start the activity:
Intent clickIntent=new Intent(context, MyConfigActivity.class);
clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
// you have the widgetId here, since it's your onUpdate
PendingIntent pendingIntent=PendingIntent
.getActivity(context, 0,
clickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.btnActivate, pendingIntent);
Moreover, to avoid duplication of code from onUpdate(), you can broadcast an intent back to the AppWidgetProvider:
Intent intent = new Intent(this,MyAppWidgetProvider.class);
intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
// Use an array and EXTRA_APPWIDGET_IDS instead of AppWidgetManager.EXTRA_APPWIDGET_ID,
// since it seems the onUpdate() is only fired on that:
int[] ids = {widgetId};
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
sendBroadcast(intent);
I know this has been answered and accepted way ago. However while I was searching the same thing I came across an awesomely simple way to update the widget.
For future readers:
The best part, this works for all the instances of the widget and from any context (Activity, Service etc)
Heres the code,
Context context = this;
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_2x1);
ComponentName thisWidget = new ComponentName(context, MyWidget.class);
remoteViews.setTextViewText(R.id.my_text_view, "myText" + System.currentTimeMillis());
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
Courtesy - Stuck :)
Instead of doing the call from your activity, I prefere to send a broad cast request to the widget for updating. The onUpdate method will be triggered and all widget layouts are passed.
Here is my code below:
1- sending broad cast from the activity:
Intent intent = new Intent(ctxt, MyAppWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
int[] ids = {R.layout.appwidget};
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
ctxt.sendBroadcast(intent);
and now, 2- implement the onUpdate method:
Intent i = new Intent(ctxt, Settings.class);
PendingIntent pi = PendingIntent.getActivity(ctxt, 0, i, 0);
for (int widgetId : allWidgetIds) {
RemoteViews remoteViews = new RemoteViews(ctxt.getPackageName(), widgetId);
remoteViews.setTextViewText(R.id.statusMsg, msg);
remoteViews.setOnClickPendingIntent(R.id.rootView, pi);
AppWidgetManager mngr = AppWidgetManager.getInstance(ctxt);
ComponentName wdgt = new ComponentName(ctxt, MyAppWidgetProvider.class);
mngr.updateAppWidget(wdgt, remoteViews);
}
That is it! I wish it helps you :)
RemoteViews view = new RemoteViews("pakagename", R.layout.widget_layout_name);
view.setTextViewText(R.id.textView_id, String.valueOf(hr + ":" + mi)); // for setting a textview
view.setCharSequence(R.id.PunchIn, "setText", "Punch In"); //for setting a button name
view.setInt(R.id.PunchIn, "setBackgroundResource", R.color.black); //for setting button color
ComponentName theWidget = new ComponentName(getActivity(), AppWidget_name.class);
AppWidgetManager manager = AppWidgetManager.getInstance(getActivity());
manager.updateAppWidget(theWidget, view);