I have an android widget that fetches data from a server every 10 minutes and display's it on the screen.
I'd like to add a "Refresh" button to that widget.
When the user clicks that button I'd like to run the method that fetches the information from the server.
Adding an event handler to a button in an application is very easy, however I couldn't find an example for a widget.
I'd like to get some help with adding a function to a button click in a widget.

- 6,595
- 12
- 42
- 64
-
1This is helpfull http://stackoverflow.com/a/8635715/2015318 – StarsSky Feb 10 '13 at 13:14
7 Answers
Here is one example more that should help:
package com.automatic.widget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
public class Widget extends AppWidgetProvider {
private static final String SYNC_CLICKED = "automaticWidgetSyncButtonClick";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews;
ComponentName watchWidget;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
watchWidget = new ComponentName(context, Widget.class);
remoteViews.setOnClickPendingIntent(R.id.sync_button, getPendingSelfIntent(context, SYNC_CLICKED));
appWidgetManager.updateAppWidget(watchWidget, remoteViews);
}
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
super.onReceive(context, intent);
if (SYNC_CLICKED.equals(intent.getAction())) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews;
ComponentName watchWidget;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
watchWidget = new ComponentName(context, Widget.class);
remoteViews.setTextViewText(R.id.sync_button, "TESTING");
appWidgetManager.updateAppWidget(watchWidget, remoteViews);
}
}
protected PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
}

- 25,338
- 6
- 61
- 78
-
2Thanks For Such Good Example I have use This code and my application Working fine....Thnks a Lots – Butani Vijay Jun 09 '13 at 12:22
-
1This code worked without the confusion other examples presented - this is an excellent, concise example of the dev guide info - thanks! – headscratch Sep 10 '13 at 18:52
-
6A note about `PendingIntent.getBroadcast(context, 0, intent, 0)`: This will cause a bug if you have more than one instance of widgets. Problem: only last widget gets updated whenever you click any instance of widget. Solution: pass widgetId to `getPendingSelfIntent` and try this: `PendingIntent.getBroadcast(context, widgetId, intent, 0)` [Detailed description](http://stackoverflow.com/a/13487623/1493081) – Alireza Mirian Jan 29 '16 at 20:04
I found out how to do that.
Add an action to the AndroidManifest.xml
file in the > <receiver><intent-filter>
tag:
<action android:name="MY_PACKAGE_NAME.WIDGET_BUTTON" />
In the provider add a constant that matches the action name:
public static String WIDGET_BUTTON = "MY_PACKAGE_NAME.WIDGET_BUTTON";
In the onUpdate()
method add a pending intent that matches the action:
Intent intent = new Intent(WIDGET_BUTTON);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.MY_BUTTON_ID, pendingIntent );
Finally, in the onRecieve() method, check the action name:
if (WIDGET_BUTTON.equals(intent.getAction())) {
//your code here
}

- 6,595
- 12
- 42
- 64
-
1I think it is interesting to note that you can (and probably should) use an explicit intent instead of an implicit intent. This means that you don't have to define the action in the manifest and that you should create the intent like this: Intent intent = new Intent(context, MyClass.class); – user936580 Mar 08 '14 at 09:19
-
Thanks! This button event listener for widget helps me a lot. Now, it's time for experiment and I have to explore more about widget making for Android. – David Dimalanta Dec 15 '14 at 04:34
-
This code is a better option than the one above as it uses explicit intent which makes it easier to call the intent from a configuration activity too – TanmayP Feb 16 '15 at 00:25
-
-
Here is another answer with the following benefits:
- It handles all App Widget instances (a user might have multiple instances of your widget in various configurations/sizes on your screen). Coding for all instances is what the official documentation prescribes. See Guide > App Widgets > Using the AppWidgetProvider Class , scroll down to the code example for "ExampleAppWidgetProvider".
- The workhorse code in
onReceive
in effect callsonUpdate
(so you reduce code duplication). - The code in
onUpdate(Context context)
is generalised so that it can be dropped into any AppWidgetProvider subclass.
The code:
public class MyWidget extends AppWidgetProvider {
private static final String ACTION_UPDATE_CLICK =
"com.example.myapp.action.UPDATE_CLICK";
private static int mCount = 0;
private static String getMessage() {
return String.valueOf(mCount++);
}
private PendingIntent getPendingSelfIntent(Context context, String action) {
// An explicit intent directed at the current class (the "self").
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
String message = getMessage();
// Loop for every App Widget instance that belongs to this provider.
// Noting, that is, a user might have multiple instances of the same
// widget on
// their home screen.
for (int appWidgetID : appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.my_widget);
remoteViews.setTextViewText(R.id.textView_output, message);
remoteViews.setOnClickPendingIntent(R.id.button_update,
getPendingSelfIntent(context,
ACTION_UPDATE_CLICK)
);
appWidgetManager.updateAppWidget(appWidgetID, remoteViews);
}
}
/**
* A general technique for calling the onUpdate method,
* requiring only the context parameter.
*
* @author John Bentley, based on Android-er code.
* @see <a href="http://android-er.blogspot.com
* .au/2010/10/update-widget-in-onreceive-method.html">
* Android-er > 2010-10-19 > Update Widget in onReceive() method</a>
*/
private void onUpdate(Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance
(context);
// Uses getClass().getName() rather than MyWidget.class.getName() for
// portability into any App Widget Provider Class
ComponentName thisAppWidgetComponentName =
new ComponentName(context.getPackageName(),getClass().getName()
);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
thisAppWidgetComponentName);
onUpdate(context, appWidgetManager, appWidgetIds);
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (ACTION_UPDATE_CLICK.equals(intent.getAction())) {
onUpdate(context);
}
}
}
The widget looks like this
This builds on the getPendingSelfIntent
work of @Kels, @SharonHaimPour and @Erti-ChrisEelmaa.
It also builds on Android-er > 2010-10-19 > Update Widget in onReceive() method (not me) where it is demonstrated how to call onUpdate from onReceive, on an App Widget instance basis. I make that code general and wrap it in callOnUpdate
.

- 1,676
- 1
- 16
- 18
protected PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
views.setOnClickPendingIntent(R.id.Timm, getPendingSelfIntent(context,
"ham"));
Also prefer URL :
How to correctly handle click events on Widget
If you solved it in a different way, please provide this as an answer
-
1I didn't understand where to put this code. Where you call the function in the click? – Sharon Haim Pour Feb 11 '13 at 07:45
-
In the pendingIntent
, we can also put extra attribute appWidgetId
to reuse it later in onReceive
to update the widget clicked widget instance
class ExampleAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray {
appWidgetIds.forEach { appWidgetId ->
Log.e("TAG", "onUpdate $appWidgetId")
val pendingRefreshClickIntent: PendingIntent = Intent(context, javaClass).let {
it.action = ACTION_REFRESH_CLICK
it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
return@let PendingIntent.getBroadcast(
context,
appWidgetId, // click in all instances widget will work well (base on Alireza Mirian comment in the top answer)
it,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
val views = RemoteViews(
context.packageName,
R.layout.example_appwidget
)
views.setOnClickPendingIntent(R.id.button_refresh, pendingRefreshClickIntent)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
Log.i("TAG", "onReceive " + intent?.action)
if (intent?.action == ACTION_REFRESH_CLICK) {
val appWidgetId = intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: return
Log.i("TAG", "onReceive appWidgetId $appWidgetId")
val appWidgetManager = AppWidgetManager.getInstance(context)
val views = RemoteViews(context!!.packageName, R.layout.example_appwidget)
views.setTextViewText(R.id.text_data, "a " + (Math.random() * 9).roundToInt())
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
companion object {
private const val ACTION_REFRESH_CLICK = "com.example.androidwidgetbuttonclick.action.ACTION_REFRESH_CLICK"
}
}
Widget initial layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/text_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AA"
android:textSize="20sp" />
<Button
android:id="@+id/button_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Refresh" />
</LinearLayout>

- 57,942
- 23
- 262
- 279
I tried the solution suggested by Sharon Haim Pour above, but my onReceive() method in AppWidgetProvider class has never been called on button press.
Intent intent = new Intent(WIDGET_BUTTON);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.MY_BUTTON_ID, pendingIntent );
After some research I could resolve the problem by updating the code as below:
Intent intent = new Intent(context, MY_APPWIDGETPROVIDER_CLASS.class);
intent.setAction(WIDGET_BUTTON);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.MY_BUTTON_ID, pendingIntent );
Do not forget to put below:
appWidgetManager.updateAppWidget(appWidgetId, views);

- 117
- 1
- 11
Unlike the other answers here which use onReceive()
, I found that it's actually a lot cleaner and simpler to do everything in onUpdate()
.
The official Android codelab Advanced Android 02.1: App widgets offers this solution. The example code there is in Java. Here I present the solution in Kotlin.
class MyAppWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context?,
appWidgetManager: AppWidgetManager?,
appWidgetIds: IntArray?
) {
appWidgetIds?.forEach { appWidgetId ->
val views = RemoteViews(
context?.packageName,
R.layout.appwidget
)
// Coroutine to perform background IO task.
GlobalScope.launch(Dispatchers.IO) {
// Suspend function.
val apiData = Api.retrofitService.getData()
updateWidgetUI(views, apiData)
context?.let {
views.setOnClickPendingIntent(
R.id.widget_button,
getUpdatePendingIntent(it, appWidgetId)
)
}
appWidgetManager?.updateAppWidget(appWidgetId, views)
}
}
}
private fun updateWidgetUI(views: RemoteViews, apiData: ApiData){
views.apply {
setTextViewText(R.id.widget_value_textview, apiData.value)
setTextViewText(
R.id.widget_last_updated_value_textview,
DateFormat.getTimeInstance(DateFormat.MEDIUM).format(Date())
)
}
}
private fun getUpdatePendingIntent(context: Context, appWidgetId: Int): PendingIntent {
val intent = Intent(context, MyAppWidgetProvider::class.java).also {
it.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
// It's very important to use intArrayOf instead of arrayOf,
// as a primitive int array is expected.
it.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(appWidgetId))
}
// Set the immutability flag for Android 12.
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
return PendingIntent.getBroadcast(
context,
appWidgetId,
intent,
flags
)
}
// No need for onReceive().
}
The key here is to use the built-int AppWidgetManager.ACTION_APPWIDGET_UPDATE
action instead of a custom action.

- 709
- 5
- 17