Updating multiple instances of App Widget in Andro

2019-07-23 11:15发布

问题:

Trying to create multiple instances of app widget and update each of them separately, but can't find our why it's not working properly. Here is the code, collected from here and modified somewhat:

package com.example.widgetagain;

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 MyWidgetProvider extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

        for (int appWidSingle = 0; appWidSingle < appWidgetIds.length; appWidSingle++) {
            // initializing widget layout
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                    R.layout.widget_main);

            // register for button event
            remoteViews.setOnClickPendingIntent(R.id.sync_button,
                    buildButtonPendingIntent(context, appWidSingle));

            // updating view with initial data
            remoteViews.setTextViewText(R.id.title, getTitle());
            remoteViews.setTextViewText(R.id.desc, getDesc());

            // request for widget update
            pushWidgetUpdate(context, remoteViews, appWidSingle);
        }

    }

    public static PendingIntent buildButtonPendingIntent(Context context, int appWidgetSingleId) {
        ++MyWidgetIntentReceiver.clickCount;

        Intent clickIntent = new Intent(context, MyWidgetIntentReceiver.class);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetSingleId);
        clickIntent.setAction("WidgetUtils.WIDGET_UPDATE_ACTION");
        return PendingIntent.getBroadcast(context, appWidgetSingleId, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        // initiate widget update request
        /*Intent intent = new Intent();
        intent.setAction("WidgetUtils.WIDGET_UPDATE_ACTION");
        return PendingIntent.getBroadcast(context, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT);*/
    }

    private static CharSequence getDesc() {
        return "Sync to see some of our funniest joke collections";
    }

    private static CharSequence getTitle() {
        return "Funny Jokes";
    }

    public static void pushWidgetUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) {

        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_main);

        Intent clickIntent = new Intent(context, MyWidgetIntentReceiver.class);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetSingleId);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetSingleId, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
        manager.updateAppWidget(appWidgetSingleId, views);
    }
}  

package com.example.widgetagain;

import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RemoteViews;

public class MyWidgetIntentReceiver extends BroadcastReceiver {
    public static int clickCount = 0;
    private String msg[] = null;
    int widgetId;

    @Override
    public void onReceive(Context context, Intent intent) {

    /*  if (intent.getAction()==null) {
            Bundle extras = intent.getExtras();
            if(extras!=null) {
                widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
                // do something for the widget that has appWidgetId = widgetId
            }
        }
        else {
            //super.onReceive(context, intent);
        }*/

        if (intent.getAction().equals("WidgetUtils.WIDGET_UPDATE_ACTION")) {

            Bundle extras = intent.getExtras();
            if(extras!=null) {
                widgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
                // do something for the widget that has appWidgetId = widgetId
            }

            updateWidgetPictureAndButtonListener(context, widgetId);
        }
    }

    private void updateWidgetPictureAndButtonListener(Context context, int widgetId) {
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                R.layout.widget_main);

        // updating view
        remoteViews.setTextViewText(R.id.title, getTitle());
        remoteViews.setTextViewText(R.id.desc, getDesc(context));

        // re-registering for click listener
        remoteViews.setOnClickPendingIntent(R.id.sync_button,
                MyWidgetProvider.buildButtonPendingIntent(context, widgetId));

        MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(),remoteViews, widgetId);
    }

    private String getDesc(Context context) {
        // some static jokes from xml
        msg = context.getResources().getStringArray(R.array.string_array_name);
        if (clickCount >= msg.length) {
            clickCount = 0;
        }
        return msg[clickCount];
    }

    private String getTitle() {
        return "Funny Jokes";
    }
}

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.widgetagain"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".MyWidgetProvider" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" />
        </receiver>

        <receiver
            android:name=".MyWidgetIntentReceiver"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="WidgetUtils.WIDGET_UPDATE_ACTION" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_info" />
        </receiver>
    </application>

</manifest>

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_main"
    android:minHeight="146dp"
    android:minWidth="292dp"
    android:previewImage="@drawable/ic_launcher"
    android:updatePeriodMillis="1000000" >
</appwidget-provider>

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5sp"
    android:background="@drawable/ic_launcher"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/buttonContainer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" >

        <Button
            android:id="@+id/sync_button"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_centerInParent="true"
            android:background="@drawable/ic_launcher"
            android:text="" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/contentContainer"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/buttonContainer"
        android:layout_alignParentTop="true"
        android:orientation="vertical"
        android:padding="8dp" >

        <TextView
            android:id="@+id/title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:maxLines="2"
            android:paddingBottom="5dp"
            android:text=""
            android:textColor="#fcfcfc"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/desc"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:maxLines="5"
            android:text=""
            android:textColor="#fcfcfc"
            android:textSize="13sp"
            android:textStyle="normal" />
    </LinearLayout>

</RelativeLayout>

回答1:

Based on what you've posted it seems that this:

// request for widget update
pushWidgetUpdate(context, remoteViews, appWidSingle);

should probably look like this instead:

// request for widget update
pushWidgetUpdate(context, remoteViews, appWidgetIds[appWidSingle]);

Likewise:

// register for button event
remoteViews.setOnClickPendingIntent(R.id.sync_button,
    buildButtonPendingIntent(context, appWidSingle));

should be:

// register for button event
remoteViews.setOnClickPendingIntent(R.id.sync_button,
    buildButtonPendingIntent(context, appWidgetIds[appWidSingle]));


回答2:

Besides the error mentioned by j__m this portion of code wasn't also correct:

public static void pushWidgetUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) {

        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_main);

        Intent clickIntent = new Intent(context, MyWidgetIntentReceiver.class);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetSingleId);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetSingleId, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
        manager.updateAppWidget(appWidgetSingleId, views);
    }

i.e was creating new remoteviews everytime instead of using passed remoteview in the pushwidgetupdate method. Hence above code is changed to:

public static void pushWidgetUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) {

        AppWidgetManager manager = AppWidgetManager.getInstance(context);

        Intent clickIntent = new Intent(context, MyWidgetIntentReceiver.class);
        clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetSingleId);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetSingleId, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteViews.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
        manager.updateAppWidget(appWidgetSingleId, views);
    }