我在使用小部件时看到了奇怪的行为。我确信它以前是有效的,但无论如何,现在不行了。不确定我改变了什么,也不确定它是否真的有效。下面的代码创建了我尝试做的事情的简化版本。一个应用程序提供了一个小部件。当它被放置在屏幕上时,系统会提示用户输入一个数字。然后,该数字将显示在小部件上。单击小部件将数字打印到日志中。可以使用不同的编号创建此小部件的多个实例。单击每个小部件应该会生成一个日志条目,该条目对应于为每个小部件选择的编号。
然而,我看到了某种缓存的行为。假设我创建了小部件3
和5
。单击3
将记录3
。单击5
将记录3
。删除3
并单击5
将再次记录3
。这是怎么回事?看起来像是创建了第一个小部件,并且缓存了它的视图?
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.developer.app">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".AppApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activity.DashboardActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.DummyWidgetConfigActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<receiver android:name=".DummyWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/dummy_widget_info" />
</receiver>
<service
android:name=".service.DummyWidgetService"
android:exported="false" />
</application>
</manifest>
DummyWidgetConfigActivity.java
package com.developer.app.activity;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.developer.app.DummyWidgetProvider;
import com.developer.app.R;
/**
* TODO: Add a class header comment!
*/
public class DummyWidgetConfigActivity extends AppCompatActivity {
private static final String TAG = "DummyWgtConfigActivity";
private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private TextView numberInput = null;
private Button submitButton = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(RESULT_CANCELED);
setContentView(R.layout.activity_dummy_config);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
numberInput = (TextView) findViewById(R.id.number_input);
submitButton = (Button) findViewById(R.id.submit);
submitButton.setOnClickListener(v -> {
try {
final int number = Integer.parseInt(numberInput.getText().toString());
onNumberSelect(number);
} catch (Exception e) {
Toast.makeText(this, "Must be a number", Toast.LENGTH_SHORT).show();
}
});
}
public void onNumberSelect(final int number) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = sp.edit();
editor.putInt("widget_" + appWidgetId, number);
editor.commit();
Log.d(TAG, "Creating widget with id " + appWidgetId);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
DummyWidgetProvider.updateAppWidget(this, appWidgetManager, appWidgetId);
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
}
DummyWidgetProvider.java
package com.developer.app;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.RemoteViews;
import com.developer.app.service.DummyWidgetService;
/**
* TODO: Add a class header comment!
*/
public class DummyWidgetProvider extends AppWidgetProvider {
private static final String TAG = "DummyWidgetProvider";
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
public static void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) {
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
final int number = sp.getInt("widget_" + appWidgetId, -1);
if (number == -1) {
Log.e(TAG, "Could not find the number associated with widget " + appWidgetId);
return;
}
Log.d(TAG, "Updating widget with id " + appWidgetId);
Intent intent = DummyWidgetService.createShowNumberIntent(context, number, appWidgetId);
PendingIntent pendingIntent = PendingIntent.getService(context, 1, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_dummy);
views.setTextViewText(R.id.widget_number, Integer.toString(number));
views.setOnClickPendingIntent(R.id.widget_number, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
DummyWidgetService.java
package com.developer.app.service;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
/**
* TODO: Add a class header comment!
*/
public class DummyWidgetService extends IntentService {
private static final String TAG = "DummyWidgetService";
private static final String DUMMY_WIDGET_SERVICE_WORKER_THREAD = "com.developer.app.THREAD.dummy_widget_service";
private static final String EXTRA_NUMBER_ID = "com.developer.app.service.DummyWidgetService.extra.NumberId";
private static final String EXTRA_WIDGET_ID = "com.developer.app.service.DummyWidgetService.extra.WidgetId";
public final static String EXTRA_ACTION = "com.developer.app.service.DummyWidgetService.extra.ACTION";
private final static int ACTION_UNKNOWN = -1;
private final static int ACTION_SHOW_NUMBER = 1;
public DummyWidgetService() {
super(DUMMY_WIDGET_SERVICE_WORKER_THREAD);
}
public static Intent createShowNumberIntent(final Context context, final int number, final int widgetId) {
Intent intent = new Intent(context, DummyWidgetService.class);
intent.putExtra(EXTRA_ACTION, ACTION_SHOW_NUMBER);
intent.putExtra(EXTRA_NUMBER_ID, number);
intent.putExtra(EXTRA_WIDGET_ID, widgetId);
return intent;
}
@Override
protected void onHandleIntent(Intent intent) {
switch (intent.getIntExtra(EXTRA_ACTION, ACTION_UNKNOWN)) {
case ACTION_SHOW_NUMBER:
final int number = intent.getIntExtra(EXTRA_NUMBER_ID, -1);
final int widgetId = intent.getIntExtra(EXTRA_WIDGET_ID, -1);
//Toast.makeText(this, "Widget number: " + number, Toast.LENGTH_SHORT).show();
Log.i(TAG, "Widget number: " + number);
break;
default:
Log.w(TAG, "Unknown action requested!");
}
}
}
dummy_widget_info.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="40dp"
android:minHeight="40dp"
android:configure="com.developer.app.activity.DummyWidgetConfigActivity"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/widget_dummy"
android:resizeMode="none"
android:widgetCategory="home_screen">
</appwidget-provider>
activity_dummy_config.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/number_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"/>
<Button
android:id="@+id/submit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Submit"/>
</LinearLayout>
widget_dummy.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/widget_number"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAlignment="center"/>
</LinearLayout>
谢谢你的建议!我确实看到其他应用程序能够正确处理多个实例。因此,我认为这完全是我的错误。
问题在于,挂起的意图是由具有相同内部ID 的同一进程(可能是Android操作系统应用程序)创建的
PendingIntent pendingIntent = PendingIntent.getService(context, 1, intent, 0);
在上面的代码中,1
用于每个小部件实例。因此,这只是重复使用了意图。该值可以更改为appWidgetId
。此外,该标志可以从0
改变为FLAG_CANCEL_CURRENT
或FLAG_UPDATE_CURRENT
。