I have a simple Widget (Android 2.1) containing just a LinearLayout, itself containing an ImageButton.
The ImageButton has a on-click listener.
The problem is: If I put several of this same widget on my home screen, some are working (listener called when button pressed), and some are not! I cannot see any pattern in which are working and which are not.
Here is the widget layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#null">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/ImageButton01"
android:src="#drawable/widget_running"
android:background="#null">
</ImageButton>
And here is the widget provider code:
public class GPAppWidgetProvider extends AppWidgetProvider {
private String mTag = getClass().getSimpleName();
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
Log.e(mTag, "onUpdate ");
// Perform this loop procedure for each App Widget that belongs to this
// provider
for (int i = 0; i < N; i++) {
Log.e(mTag, "widget onUpdate one loop");
int appWidgetId = appWidgetIds[i];
// Create an Intent
Intent intent = new Intent(context, GPService.class).setAction(ACTION_WIDGET_TOGGLE_PAUSE);
intent.putExtra("widgetId", appWidgetId);
PendingIntent pauseIntent = PendingIntent.getService(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.gp_appwidget);
views.setOnClickPendingIntent(R.id.ImageButton01, pauseIntent);
// widget update
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
I had the same problem.
Don't forget to set a different "requestCode" when you call "getService" :
public static PendingIntent getService (Context context, int requestCode, Intent intent, int flags)
And make sure your "appWidgetId" is different for each widget.
Related
I would like to make a custom image for a widget, i tried
views.setImageViewResource(R.id.red_button, R.drawable.button_default);
and
Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.button_default);
views.setImageViewBitmap(R.id.red_button, icon);
but it says problem loading widget all the time, no matter what I try, am I missing something? can someone point me to the right documantion/what to do?
Edit:
full xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_green_dark"
android:orientation="vertical"
android:padding="#dimen/widget_margin">
<ImageButton
android:id="#+id/red_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button"
app:srcCompat="#drawable/button_default" />
</LinearLayout>
code:
public class NewAppWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = context.getString(R.string.appwidget_text);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.red_button, pi);
views.setTextViewText(R.id.red_button, widgetText);
Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
R.drawable.button_default);
views.setImageViewBitmap(R.id.red_button, icon);
//views.setImageViewResource(R.id.red_button, R.drawable.button_default);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}
Thanks!
The error message ("problem loading widget") is not caused by any problems with displaying the drawable, it is showing because of this line in your code:
views.setTextViewText(R.id.red_button, widgetText);
You can only use setTextViewText(int, CharSequence) with resource ids for Views extending from TextView (according to the docs, it's equivalent to TextView.setText(CharSequence) ).
The resource id R.id.red_button belongs to an ImageButton which extends from ImageView not from TextView, that's why you get the error message.
So if you want to show some text you need to add a Textview to your app widget's layout.
Hello this is simple question
i create widget and test this is my simple code :
#Override
public void onReceive(Context context, Intent intent) {
ComponentName thisAppWidget = new ComponentName(context, MyWidget.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
Log.d(" widget ids : " + Arrays.toString(ids) );
setResultCode(0);
}
But i have got red square on home screen .. ?
My widget provider configuration :
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="80dp"
android:minHeight="80dp"
android:previewImage="#drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:widgetCategory="home_screen|keyguard"
>
</appwidget-provider>
But i have got red square on home screen .. ?
This could be the preview image you have set in widget provider xml.
When the widget is added in home screen, the onUpdate() method will be called, where you can set the remote layout for the widget like this.
public class CustomAppWidgetProvider extends AppWidgetProvider{
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
You can also set a pending intent to an activity/service to be invoked when the whole widget or an child item in the widget is clicked
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context,0,intent,0);
remoteViews.setOnClickPendingIntent(R.id.imageView1,pendingIntent);
So, here in the widget layout there is a textview , and when the user click on the textview the MainActivity will be launched.
You have to set an layout file to your appwidget-provider:
android:initialLayout="#layout/widget_view"
In this layout file you have to put Buttons, Images, TextViews etc. whatever you need.
I am trying to make a widget for my app, and I want it to be with a buttonm progress bar and text view, which would later be changed, so I need to somehow work with the views themselves, like I can from an activity, show a view, hide a view, change a button background etc...
I tried tweaking with the sample code from the Android documentations, but I can only start an activity with this
public class WidgetProvider extends AppWidgetProvider {
#Override
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];
Intent intent = new Intent(context, ActivityMain.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
}
Does the widget need to be connected to an activity in order to make actions (connect to the internet, write in the database, write in the objects of the apps instance (if there is one))? And can I work with views the way I am asking?
Outside of setting on-click PendingIntents on views, there isn't much you can do inside of a widget. The standard recipe is:
Make a PendingIntent that sends a broadcast (PendingIntent.getBroadcast()) and set it on the appropriate view in your widget.
In the BroadcastReceiver that receives the intent, you update the widget to show a spinner and start a Service to do whatever long-running work you want to do (e.g connect to the internet).
Once that work is done, you can update your widget again and remove the spinner.
I have the following code in my sample app. I'm starting a service from an app widget when a button is clicked. The service's job is to play a short audio clip that depends on which button was clicked.
The app widget contains two buttons (PREV and NEXT). On click events are handled in onUpdate().
From different guides that I've found online I can start the service in two ways:
by creating a broadcast in onUpdate() method and handle it later in onReceive() method of the extended AppWidgetProvider class (as in the sample code for PREV button).
or by calling startService() via a PendingIntent in onUpdate() (as NEXT button).
Which of both is better practice or more commonly used? Thank you
<!-- widget_player.xml -->
<LinearLayout
android:id="#+id/player_controls"
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/btn_player_prev"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#android:drawable/ic_media_previous" />
<ImageButton
android:id="#+id/btn_player_next"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="#android:drawable/ic_media_next" />
</LinearLayout>
WidgetPlayer class
public class WidgetPlayer extends AppWidgetProvider {
public static String ACTION_WIDGET_PREV = "action.WIDGET_PREV";
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int nPlayerWidgets = appWidgetIds.length;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_player);
for (int i = 0; i < nPlayerWidgets; i++) {
int appWidgetId = appWidgetIds[i];
updateWidgetPlayer(context, appWidgetManager);
Intent intent;
PendingIntent actionPendingIntent;
// PREV button
intent = new Intent(context, WidgetPlayer.class);
intent.setAction(ACTION_WIDGET_PREV);
actionPendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_player_prev, actionPendingIntent);
// NEXT button (not using a broadcast)
intent = new Intent(context, PlayerService.class);
intent.setAction(PlayerService.ACTION_NEXT);
actionPendingIntent = PendingIntent.getService(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.btn_player_next, actionPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager manager = AppWidgetManager.getInstance(context.getApplicationContext());
if (intent.getAction().equals(ACTION_WIDGET_PREV)) {
Intent iPrev = new Intent(PlayerService.ACTION_PREV);
iPrev.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetMetaPlayerIds);
context.startService(iPrev);
updateWidgetPlayer(context, manager);
}
// handle more actions here
else {
super.onReceive(context, intent);
}
}
}
The NEXT button code looks more concise so it is better choice if it does what you want. With the PREVIOUS code you have the extra step of receiving the broadcast which appears unnecessary.
You can pass along the id's in the intent to the service if you need those.
I created a class that downloads some text from the internet and I want to take that text and update a TextView in my widget. I know that the event (OnDownloadCompleteListener) is getting triggered because I'm Logging it but I can't figure out how to update the TextView from within that event. I know it's a newbie mistake, just not sure what I'm missing.
public class Widget extends AppWidgetProvider{
InternetText internettext; //Handles downloading the text from the internet
RemoteViews views;
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
// Perform this loop procedure for each App Widget that belongs to this provider
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// Create an Intent to launch ExampleActivity
Intent intent = new Intent(context, MainActivity.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
views = new RemoteViews(context.getPackageName(), R.layout.widget);
views.setOnClickPendingIntent(R.id.tvWidgetVerse, pendingIntent);
internettext = new InternetText(context);
internettext.setOnDownloadCompleteListener(new OnDownloadCompleteListener() {
#Override
public void onEvent() {
TheText thetext = internettext.downloadedText(); //The text object
Log.i("", "Widget Text Downloaded " + thetext.getText()); //This fires so I know we've downloaded the text
TextStyling textStyle = new TextStyling();
//*****THIS IS WHERE I'M HAVING THE PROBLEM********
views.setTextViewText(R.id.tvWidgetText, Html.fromHtml(textStyle.boldWords(thetext.getText()))); //this never updates
}
});
internettext.getText();
// Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Ok, I figured it out. I have to call appWidgetManager.updateAppWidget() from within the event. I knew it was a no-brainer...
appWidgetManager.updateAppWidget(appWidgetId, views);
which also means I have to make appWidgetManager and appWidgetId final
public void onUpdate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds) {
...
}