窗口小部件问题:退出主应用程序会重置窗口小部件

时间:2018-06-10 09:06:42

标签: android android-widget

我有一个带按钮的小部件。在我的app小部件(TestWidget.java)中,我将一个私有静态布尔变量(buttonClicked)初始化为false。

当我点击按钮时,布尔buttonClicked设置为true。我有一个updatePeriodMillis设置为最小30分钟(1800000毫秒)。

首先onUpdate来了:buttonClicked值为true。正如所料。

然后我停止了我的主应用程序。以下onUpdates将buttonClicked值显示为false。

launch --> 06-10 10:55:56.365 4186-4186/com.narb.testwidget I/TESTWID: update setButtonClicked false
1st onUpdate after button click --> 06-10 10:56:11.685 4186-4186/com.narb.testwidget I/TESTWID: setButtonClicked true
onUpdate after main app exit --> I/TESTWID: update setButtonClicked false

为什么?

App小部件 - TestWidget

public class TestWidget extends AppWidgetProvider {
    private static RemoteViews views;
    private static boolean buttonClicked = false;

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // Get all ids
        ComponentName thisWidget = new ComponentName(context,
                TestWidget.class);
        int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

        Log.i("TESTWID", "update setButtonClicked "+buttonClicked);

        views = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        views.setOnClickPendingIntent(R.id.wid_btn_tst, setButton(context));

        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    public static void setButtonClicked(boolean b){
        buttonClicked = b;
        Log.i("TESTWID", "setButtonClicked "+buttonClicked);
    }

    public static PendingIntent setButton(Context context) {
        Intent intent = new Intent();
        intent.setAction("TEST");
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
        ComponentName myWidget = new ComponentName(context, TestWidget.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(myWidget, remoteViews);
    }

}

按钮代码 - TestWidgetReceiver

public class TestWidgetReceiver extends BroadcastReceiver{
    private static boolean isButtonON = false;

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals("TEST")){
            updateWidgetButton(context, 2);
        }
    }

    private void updateWidgetButton(Context context, int index) {
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.test_widget);
        if(index == 2) {
            if(isButtonON) {
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test Off");
                isButtonON = false;
            }
            else{
                remoteViews.setTextViewText(R.id.wid_btn_tst, "Test On");
                isButtonON = true;
                TestWidget.setButtonClicked(isButtonON);
            }
            //REMEMBER TO ALWAYS REFRESH YOUR BUTTON CLICK LISTENERS!!!
            remoteViews.setOnClickPendingIntent(R.id.wid_btn_tst, TestWidget.setButton(context));
        }

        TestWidget.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
    }

}

清单

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="Test"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <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=".TestWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

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

        <receiver
            android:name=".TestWidgetReceiver"
            android:label="widgetBroadcastReceiver" >
            <intent-filter>
                <action android:name="TEST" />
            </intent-filter>

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

    </application>

2 个答案:

答案 0 :(得分:2)

  

在我的app小部件(TestWidget.java)中,我将私有静态布尔变量(buttonClicked)初始化为false

static变量充其量只是一个缓存。

  

然后我停止了我的主应用程序。

我不确切地知道你的意思。我的猜测是,您的意思是从概览屏幕中删除与您的应用关联的任务。

  

以下onUpdates将buttonClicked值显示为false。那是为什么?

如果通过“停止我的主应用程序”,你做了我概述的事情,你将终止你的过程。稍后,例如当您点击应用小工具按钮时,Android会为您启动一个全新的流程,此时您的static字段,此时您的静态字段将成为其默认值。

  

我原以为小部件有自己的内存副本,因为即使主应用程序退出也会继续运行?

没有。主屏幕中将存在与您的应用小部件相关联的视图。这不包括您的TestWidget代码,该代码不属于主屏幕。

  

我正在考虑放弃这种方法,以低刷新时间(10秒)执行alarmManager。

首先,这在Android 5.1及更高版本上是不可能的,因为它会大大耗尽电池电量。其次,它并不能保证您的流程能够保持不变。

static个变量充其量只是一个缓存。任何应用程序,包括具有应用程序小部件的应用程序,都需要在其他地方存储重要数据:SharedPreferences,SQLite数据库,其他类型的文件,服务器等。

答案 1 :(得分:1)

如果您强制停止应用程序或系统因内存不足而决定停止应用程序,则会从内存中删除所有类,并且所有静态变量都将丢失。在这种情况下,您应该将数据保存到DB或SharedPreferences或类似数据,或者重新考虑方法本身。是否真的有必要按照你在这里的方式去做?