Configuration Activity doesn't update the App Widget

1.2k views Asked by At

"developers.android.com" at this page says:

The onUpdate() method will not be called when the App Widget is created (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity is launched). It is the responsibility of the configuration Activity to request an update from the AppWidgetManager when the App Widget is first created.

Then shows an example for "Updating the App Widget from the configuration Activity" in the next section.

So I created a project according to its instructions (and by the help of some other resources) but the onUpdate() method (and also the onReceive(...) method) would not be called from the configuration Activity.

  • Expected Result (logcat window):
    XXXX:: ConfigureActivity onCreate(...) method: Started.
           Expected occurring FIRST: when the widget has been inserted.

    XXXX:: ConfigureActivity: Finished.
           Expected occurring LAST: when OK button has been clicked.

    XXXX:: AppWidgetProvider onUpdate(...) method: Started.
           Expected occurring LAST: when OK button has been clicked.
  • Real Result (logcat window):

    1- First (16:59:31): when the widget has been inserted (Problem is here!):

    12-21 16:59:31.688 I/XXXX: AppWidgetProvider onUpdate(...) method: Started.
                        Expected occurring LAST: when OK button has been clicked.
    

    2- First (16:59:31): when the widget has been inserted:

    12-21 16:59:31.743 I/XXXX: ConfigureActivity onCreate(...) method: Started.
                        Expected occurring FIRST: when the widget has been inserted.
    

    3- Last (17:00:52): when OK button has been clicked:

    12-21 17:00:52.063 I/XXXX: ConfigureActivity: Finished.
                        Expected occurring LAST: when OK button has been clicked.
    

    For more information about real result see the end.


This is my source:

  • AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <application>

        <activity
            android:name=".MainActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver android:name="ExampleAppWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/example_appwidget_info" />
        </receiver>

        <activity android:name=".ExampleAppWidgetConfigure">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
            </intent-filter>
        </activity>

    </application>

</manifest>
  • res/xml/example_appwidget_info.xml:
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:configure="com.example.myapp.ExampleAppWidgetConfigure"
    android:initialLayout="@layout/example_appwidget"
    android:minHeight="40dp"
    android:minWidth="40dp"
    android:previewImage="@drawable/widget_preview"
    android:updatePeriodMillis="86400000">
</appwidget-provider>
  • res/layout/example_appwidget.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Click Me"/>

</RelativeLayout>
  • ExampleAppWidgetProvider.java:
...
public class ExampleAppWidgetProvider extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        Log.i("XXXX", "AppWidgetProvider onUpdate(...) method: Started.\n" +
                "Expected occurring LAST: when OK button has been clicked.");
        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
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("XXX", "AppWidgetProvider onReceive(...) method: Started: " + intent.getAction());
        super.onReceive(context, intent);
    }
}
  • res/layout/activity_widget_configuration.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/ok_btn"
        android:layout_marginTop="30dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="OK" />

</LinearLayout>
  • ExampleAppWidgetConfigure.java:
...
public class ExampleAppWidgetConfigure extends Activity {
    private int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i("XXXX", "ConfigureActivity onCreate(...) method: Started.\n" +
                "Expected occurring FIRST: when the widget has been inserted.");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_widget_configuration);

        final Button OK_btn = (Button) findViewById(R.id.ok_btn);

        OK_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Context context = getApplicationContext();

                // 1. First, get the App Widget ID from the Intent that launched the Activity:
                Intent intent = getIntent();
                Bundle extras = intent.getExtras();
                if (extras != null) {
                    mAppWidgetId = extras.getInt(
                            AppWidgetManager.EXTRA_APPWIDGET_ID,
                            AppWidgetManager.INVALID_APPWIDGET_ID);
                }

                // 2. Perform your App Widget configuration:
                    /* Nothing. */

                // 3. When the configuration is complete, get an instance of the AppWidgetManager
                //    by calling getInstance(Context):
                AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

                // 4. Update the App Widget with a RemoteViews layout by calling
                //    updateAppWidget(int, RemoteViews):
                RemoteViews views = new RemoteViews(context.getPackageName(),
                        R.layout.example_appwidget);
                appWidgetManager.updateAppWidget(mAppWidgetId, views);

                // 5. Finally, create the return Intent, set it with the Activity result,
                //    and finish the Activity:
                Intent resultValue = new Intent();
                resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
                setResult(RESULT_OK, resultValue);

                Log.i("XXXX", "ConfigureActivity: Finished.\n" +
                        "Expected occurring LAST: when OK button has been clicked.");
                finish();
            }
        });
    }
}

Where is the problem? Or I expected wrongly?


EXTRA INFORMATION:

More accurate real result:

12-21 16:59:31.685 13598-13598/com.example.myapp I/XXX: AppWidgetProvider onReceive(...) method: Started: android.appwidget.action.APPWIDGET_ENABLED
12-21 16:59:31.687 13598-13598/com.example.myapp I/XXX: AppWidgetProvider onReceive(...) method: Started: android.appwidget.action.APPWIDGET_UPDATE
12-21 16:59:31.688 13598-13598/com.example.myapp I/XXXX: AppWidgetProvider onUpdate(...) method: Started.
                                                          Expected occurring LAST: when OK button has been clicked.
12-21 16:59:31.743 13598-13598/com.example.myapp I/XXXX: ConfigureActivity onCreate(...) method: Started.
                                                          Expected occurring FIRST: when the widget has been inserted.

12-21 17:00:52.063 13598-13598/com.example.myapp I/XXXX: ConfigureActivity: Finished.
                                                          Expected occurring LAST: when OK button has been clicked.
1

There are 1 answers

1
Mike On

Try moving this code outside of the onClickListener. Also, verify that mAppWidgetId is not equal to AppWidgetManager.INVALID_APPWIDGET_ID.

Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
    mAppWidgetId = extras.getInt(
            AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID);
}

Barring that... assuming your configuration activity is actually opening when you add a widget... and that your code really is in the com.example.myapp package... I'm not sure what is going on. Perhaps it is something with the RemoteViews. Instead of using the AppWidgetManager in your OnClickListener, just send an intent to the receiver directly like this.

Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, ExampleAppWidgetProvider.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {mAppWidgetId});
sendBroadcast(intent);

Original answer:

This looks very similar to the Guide. The only thing that is a little strange is this line

final Context context = getApplicationContext();

Try removing that line and doing this instead

...
final Button OK_btn = (Button) findViewById(R.id.ok_btn);
final Context context = this;
OK_btn.setOnClickListener(new View.OnClickListener() {
...