Xin chúc mừng, bạn đã gặp phải appwidgets ảo. Dường như nó được ghi lại trên Android issue tracker. Chúng thường xảy ra khi hoạt động cấu hình cho appwidget bị hủy, mặc dù nó có vẻ là thông qua việc triển khai không đúng hoạt động cấu hình; các nhà phát triển bỏ bê bao gồm ID appwidget như một phần bổ sung khi đặt kết quả hoạt động thành RESULT_CANCELED
. (Ứng dụng ApiDemos mẫu thậm chí của Google bỏ qua để làm điều này!)
Việc thực hiện đúng là như thế này:
public class AppWidgetConfigActivity extends Activity {
private int appWidgetId;
private Intent resultValue;
protected void onCreate(bundle saved) {
super.onCreate(saved);
// get the appwidget id from the intent
Intent intent = getIntent();
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
// make the result intent and set the result to canceled
resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
setResult(RESULT_CANCELED, resultValue);
// if we weren't started properly, finish here
if (appwidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
/* ... */
}
/* ... */
private void finishConfigure() {
/* finish configuring appwidget ... */
setResult(RESULT_OK, resultValue);
}
}
Như vậy đến nay tôi biết có cách nào để phát hiện sự hiện diện của một appwidget phantom mà không làm sổ sách kế toán của riêng bạn . Tôi khuyên bạn nên lưu trữ giá trị SharedPreferences cho biết hoạt động cấu hình không bị hủy và sau đó truy vấn giá trị này trong mã khác của bạn. Bạn cũng có thể sử dụng thông tin này để "xóa" một tiện ích con ảo nếu bạn gặp phải. Trong hoạt động cấu hình appwidget của bạn:
private void finishConfigure() {
/* finish configuring appwidget ... */
setResult(RESULT_OK, resultValue);
String key = String.format("appwidget%d_configured", appwidgetId);
SharedPreferences prefs = getSharedPreferences("widget_prefs", 0);
prefs.edit().putBoolean(key, true).commit;
}
Sau đó, bạn có thể kiểm tra xem bạn có ít nhất một phi phantom appwidget như vậy:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
AppWidgetHost appWidgetHost = new AppWidgetHost(context, 1); // for removing phantoms
SharedPreferences prefs = getSharedPreferences("widget_prefs", 0);
boolean hasWidget = false;
int[] appWidgetIDs = appWidgetManager.getAppWidgetIds(new ComponentName(context, Widget.class));
for (int i = 0; i < appWidgetIDs.length; i++) {
int id = appWidgetIDs[i];
String key = String.format("appwidget%d_configured", id);
if (prefs.getBoolean(key, false)) {
hasWidget = true;
} else {
// delete the phantom appwidget
appWidgetHost.deleteAppWidgetId(id);
}
}
if (hasWidget) {
// proceed
} else {
// turn off alarms
}
Câu trả lời này xứng đáng hơn rất nhiều tiếng tăm! Tôi tin rằng rất nhiều người sẽ gặp phải vấn đề này (ngay cả khi họ không biết điều đó) vì mã appwidget "hello world" mẫu mà bạn nhận được từ Android Studio không thực hiện đúng cách và đó là nơi rất nhiều của mọi người sẽ bắt đầu. Với lời khuyên của bạn để bao gồm ID appwidget như một phần bổ sung khi đặt kết quả hoạt động thành 'RESULT_CANCELED', tôi dường như không tạo bất kỳ tiện ích ảo nào nữa. Cảm ơn! – drmrbrewer
Đối với mã để xóa các vật dụng ảo * nên * chúng xuất hiện vì bất kỳ lý do gì, bạn muốn giới thiệu nó ở đâu? Không có trong 'onUpdate()' bởi vì dường như nó được gọi khi một hoạt động config được mở lần đầu tiên, trước khi widget được cấu hình - không muốn giết tiện ích trước khi nó được sinh ra! – drmrbrewer
Câu trả lời rất hữu ích và được viết tốt. Cảm ơn. – dazed