When we click the widget at that time I need to open an activity screen (or application). How to do this?
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);
Check this out
Processing more than one button click at Android Widget
Include this code in yout WidgetProvider class's onUpdate() method.
for(int j = 0; j < appWidgetIds.length; j++)
{
int appWidgetId = appWidgetIds[j];
try {
Intent intent = new Intent("android.intent.action.MAIN");
intent.addCategory("android.intent.category.LAUNCHER");
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setComponent(new ComponentName("your Application package",
"fully qualified name of main activity of the app"));
PendingIntent pendingIntent = PendingIntent.getActivity(
context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
layout id);
views.setOnClickPendingIntent(view Id on which onclick to be handled, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
} catch (ActivityNotFoundException e) {
Toast.makeText(context.getApplicationContext(),
"There was a problem loading the application: ",
Toast.LENGTH_SHORT).show();
}
}
The Android developer pages for App Widgets has information and a full example doing exactly this: http://developer.android.com/guide/topics/appwidgets/index.html
Using Kotlin
You need to add PendingIntent on Click of your widget Views
remoteViews.setOnClickPendingIntent(R.id.widgetRoot,
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0))
Where widgetRoot is the id of my widget's parent ViewGroup
In On Update
Pending intent is usually added in onUpdate callback
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray) {
// There may be multiple widgets active, so update all of them
val widgetIds = appWidgetManager.getAppWidgetIds( ComponentName(context, ClockWidget::class.java))
for (appWidgetId in widgetIds) {
// Construct the RemoteViews object
val remoteViews = RemoteViews(context.packageName, R.layout.clock_widget)
//Open App on Widget Click
remoteViews.setOnClickPendingIntent(R.id.weatherRoot,
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0))
//Update Widget
remoteViews.setTextViewText(R.id.appWidgetText, Date().toString())
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
}
very simple(In xamarin c# android mono):
public override void OnReceive(Context context, Intent intent)
{
if (ViewClick.Equals(intent.Action))
{
var pm = context.PackageManager;
try
{
var packageName = "com.companyname.YOURPACKAGENAME";
var launchIntent = pm.GetLaunchIntentForPackage(packageName);
context.StartActivity(launchIntent);
}
catch
{
// Something went wrong :)
}
}
base.OnReceive(context, intent);
}
Related
I'm creating an android widget that by clicking, every instance of the widget will go to a different url.
I'm having a problem sending the url from the 'onUpdate' to the 'onReceive' method.
The onUpdate code:
List<String> urls = Arrays.asList("google.com", "yahoo.com", "bing.com", "msn.com");
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
int cnt = 0;
// Get all ids
ComponentName thisWidget = new ComponentName(context,MyWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds) {
// create some random data
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
Log.w("WidgetExample", urls.get(cnt));
// Set the text
remoteViews.setTextViewText(R.id.urlData, urls.get(cnt));
// Register an onClickListener
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
intent.putExtra("url",urls.get(cnt));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.open, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
cnt++;
}
}
The onReceive code:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String TAG = "onReceive";
Bundle extras = intent.getExtras();
if(extras!=null) {
String url = extras.getString("url");
Log.d(TAG, "url is : "+url);
}else {
Log.d(TAG, "no url");
}
}
The problem is that i allwas get the same url (the last one in the list - 'msn.com').
Thank's allot
Avi
I think that this append because you override everytime the intent storage in PendingIntent because the requestCode doesn't change.
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,**0**, intent, PendingIntent.FLAG_UPDATE_CURRENT);
If you want set more PendingIntent you must change the requestCode (0 in your case)
Try
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, cnt, intent, PendingIntent.FLAG_UPDATE_CURRENT);
In this way all PendingIntents are different...
You're using PendingIntent.FLAG_UPDATE_CURRENT which, as the documentation states, "[...]if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent[...]"
So since you're trying to create multiple instances of the same class (PendingIntent) that flag is causing the unwanted behaviour. It is updating the previously instantiated object (the first time you called PendingIntent.getBroadcast(...) method) and changes the field(s) of that object and returns it. So that all your calls end up with the last extra (last URL you supplied) .
I have implemented a widget with an ImageButton and a TextView. That ImageButton launch an activity when its clicked. This activity updates the widget text with what the user writes on the activity EditText. Now the problem is that I only know how to get the ids like this:
for (int widgetId : allWidgetIds) {
// Create some random data
int number = (new Random().nextInt(100));
RemoteViews remoteViews = new RemoteViews(getApplicationContext()
.getPackageName(), R.layout.widget_layout);
Log.w("WidgetExample", String.valueOf(number));
//Here I should set text from edit text, but I'm using a random for testing.
remoteViews.setTextViewText(R.id.textView1,
"Random: " + String.valueOf(number));
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
This code will obviously change the data of all the ids, since its inside a for. Is there anyway that I can past the clicked widgetId with my intent, so I can eliminate that for? This is my widgetProvider:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// Get all ids
ComponentName thisWidget = new ComponentName(context, Widget.class);
allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int widgetId : allWidgetIds) {
Intent i = new Intent(context, WidgetSetup.class);
i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
i.setFlags(i.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
// Create some random data
int number = (new Random().nextInt(100));
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
// Set the text
remoteViews.setTextViewText(R.id.textView1, String.valueOf(number));
Intent active = new Intent(context, Widget.class);
active.setAction(ACTION_WIDGET_REFRESH);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.imageButton1, actionPendingIntent);
active = new Intent(context, Widget.class);
active.setAction(ACTION_WIDGET_SETTINGS);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.imageButton2, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_REFRESH)) {
//Log.i("onReceive", ACTION_WIDGET_REFRESH);
Intent i = new Intent(context, MainActivity.class);
i.setFlags(i.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} else if (intent.getAction().equals(ACTION_WIDGET_SETTINGS)) {
//Log.i("onReceive", AppWidgetManager.EXTRA_APPWIDGET_ID);
Intent i = new Intent(context, WidgetSetup.class);
i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
//Here I tried to pass the widgetID with no luck.
//i.putExtra(pass widget id?);
i.setFlags(i.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
} else {
super.onReceive(context, intent);
}
}
Thanks
For a running example have a look at my code for MiniCallWidget lines 97 and 169.
Add an Extra to the intent you launch onClick and create in the for loop that specifies the ID of the current widget being setup.
Then retrieve the ID from the extras in the receiving Activity, and pass it back when you're done. Then use the returned ID to make changes only to one widget.
You can do this by having an if-else that also checks for a flag that tells whether or not you're updating only one widget.
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.
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);
}
}
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
}
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 calls onUpdate (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.
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
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>
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);
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.
I have a widget that has a refresh button and a textview. Refresh updates the content and when user clicks on textview it starts a new activity.
Problem is it works fine for a few hours and then onclick and refresh button doesn't do anything. Nothing is captured in logcat. Also If user deletes widget and put a new one it starts working for a few hours and then the same story :(...what am I doing wrong!
Broadcast receiver.
onUpdate
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
long interval = getrefresInterval();
final Intent intent = new Intent(context, UpdateService.class);
final PendingIntent pending = PendingIntent.getService(context, 0, intent, 0);
final AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
alarm.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(),interval, pending);
// Build the intent to call the service
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget);
// To react to a click we have to use a pending intent as the
// onClickListener is excecuted by the homescreen application
Intent ClickIntent = new Intent(context.getApplicationContext(),widgetHadith.class);
Intent UpdateIntent = new Intent(context.getApplicationContext(),UpdateService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context.getApplicationContext(), 0, ClickIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntentUpdate = PendingIntent.getService(context.getApplicationContext(), 0, UpdateIntent,
PendingIntent.FLAG_UPDATE_CURRENT); //use this to update text on widget. if use this put UpdateService.class to intent
remoteViews.setOnClickPendingIntent(R.id.widget_textview, pendingIntent);
remoteViews.setOnClickPendingIntent(R.id.widget_refresh, pendingIntentUpdate);
// Finally update all widgets with the information about the click listener
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
// Update the widgets via the service
context.startService(intent);
}
onReceive
public void onReceive(Context context, Intent intent) {
// v1.5 fix that doesn't call onDelete Action
final String action = intent.getAction();
if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
final int appWidgetId = intent.getExtras().getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
this.onDeleted(context, new int[] { appWidgetId });
}
} else {
super.onReceive(context, intent);
}
}
onDelete
public void onDeleted(Context context, int[] appWidgetIds) {
// Toast.makeText(context, "onDelete", Toast.LENGTH_SHORT).show();
super.onDeleted(context, appWidgetIds);
}
Service onstart where I am updating
#Override
public void onStart(Intent intent, int startId) {
RemoteViews updateViews = new RemoteViews(this.getPackageName(),R.layout.widget);
processDatabase();
Spanned text = LoadHadith();
String hadith = text.toString();
Log.d("BR", "service---> ");
// set the text of component TextView with id 'message'
updateViews.setTextViewText(R.id.widget_textview, text);
//Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(this, HelloWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
The problem is that you can't do a partiall update for a widget, you must set all the widget features, such as the set of PendingIntent's every time you push a new remoteView.
(Partiall updates are only available for API14 and up...).
The reason your widgets are loosing their pendingIntents is that the android system saves the remoteView, and rebuilds your widget with it, in case it resets the widget (shortage of memmory, TaskManager/taskKiller in use, etc...), so you must set all the update code for the widget in the remoteView in your updateService.
Otherwise, it's just won't set the pendingIntents again.
So just add the code setting the pendingIntents to the service and your problem will be solved =]
Would like a button in my widget to fire the APPWIDGET_UPDATE intent on the widget class to force an update, but I dont see APPWIDGET_UPDATE as a static field in Intent.
Is this possible, and how would one do this?
Intent intent = new Intent(context, BaseWidgetProvider.class);
intent.setAction({APPWIDGET_UPDATE INTENT HERE})
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.MyWidgetButton, pendingIntent);
Yes, it's possible. You'll find the action in AppWidgetManager:
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
Edit: You will need to provide the ids of the widgets you want to update. Below is a complete sample.
AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
ComponentName widgetComponent = new ComponentName(context, YourWidget.class);
int[] widgetIds = widgetManager.getAppWidgetIds(widgetComponent);
Intent update = new Intent();
update.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);
update.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
context.sendBroadcast(update);
I know this is a very old question, but I think this might be interesting, because Android updated the AppWidgets refresh policies. I think this change could prevent the exising answer to work as expected.
This is my solution, using RemoteViews and a collection.
public static final String ACTION_WIDGET_UPDATE = "com.yourpackage.widget.ACTION_UPDATE";
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_UPDATE)) {
int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);
AppWidgetManager.getInstance(context)
.notifyAppWidgetViewDataChanged(widgetId, R.id.widgetColectionRoot);
}
super.onReceive(context, intent);
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
for (int widgetId : appWidgetIds) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
RemoteViews collectionRemoteView = getRemoteViews(widgetId, context);
appWidgetManager.updateAppWidget(widgetId, collectionRemoteView);
}
}
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#SuppressWarnings("deprecation")
private RemoteViews getRemoteViews(int widgetId, Context context) {
// Sets up the intent that points to the RemoteViewService
// that will
// provide the views for this collection.
Intent widgetUpdateServiceIntent = new Intent(context,
RemoteViewsService.class);
widgetUpdateServiceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
// When intents are compared, the extras are ignored, so we need
// to embed the extras
// into the data so that the extras will not be ignored.
widgetUpdateServiceIntent.setData(
Uri.parse(widgetUpdateServiceIntent.toUri(Intent.URI_INTENT_SCHEME)));
RemoteViews collectionRemoteView = new RemoteViews(context.getPackageName(),
R.layout.widget_collection);
collectionRemoteView.setRemoteAdapter(widgetId,
R.id.widgetColectionRoot, widgetUpdateServiceIntent);
collectionRemoteView.setEmptyView(R.id.widgetColectionRoot, R.id.widgetEmpty);
// This section makes it possible for items to have
// individualized behavior.
// It does this by setting up a pending intent template.
// Individuals items of a collection
// cannot set up their own pending intents. Instead, the
// collection as a whole sets
// up a pending intent template, and the individual items set a
// fillInIntent
// to create unique behavior on an item-by-item basis.
Intent selectItemIntent = new Intent(context,
BrochuresWidgetProvider.class);
Intent refreshIntent = new Intent(selectItemIntent);
refreshIntent.setAction(ACTION_WIDGET_UPDATE);
PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(
context, 0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
collectionRemoteView.setOnClickPendingIntent(R.id.widgetReload,
refreshPendingIntent);
return collectionRemoteView;
}
Of course, you also need to register that intent-filter on your manifest, inside your widget provider declaration.