如何修复更新小部件的 ANR 错误
How to fix ANR error for updating widgets
我有一个 JobScheduler 服务触发更新小部件 UI。
@Override
public boolean onStartJob(final JobParameters params) {
//Offloading work to a new thread.
new Thread(() -> {
try {
// Here we receive updated data and store to SharedPreferences
...
MyWidgetProvider.updateWidgets(getApplicationContext());
} catch (Exception e) {
Log.e(TAG, "onStartJob: " + e.getMessage());
} finally {
jobFinished(params, false);
}
}).start();
return true;
}
我的 AppWidgetProvider:
protected static void updateWidget(Context context) {
try {
ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class);
int[] appWidgetIds = AppWidgetManager.getInstance(context.getApplicationContext()).getAppWidgetIds(thisWidget);
if (appWidgetIds != null) {
if (appWidgetIds.length > 0) {
for (int appWidgetId : appWidgetIds) {
try {
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setAction(UPDATE_WIDGET);
context.sendBroadcast(intent);
} catch (Exception e) {
}
}
}
}
} catch (Exception e) {
Log.e(TAG, "error" + e.getMessage());
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
try {
Bundle extras = intent.getExtras();
String action = intent.getAction();
if (extras != null && !TextUtils.isEmpty(action)) {
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
if (action.equals(UPDATE_WIDGET)) {
RemoteViews remoteViews = getRemoteView(context);
// Here read from the SharedPreferences and updates the remoteViews
....
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews);
}
}
}
} catch (Exception e) {
Log.e(TAG, "onReceive() error: " + e.getMessage());
}
}
我在意图广播时遇到 ANR 错误 { act=.....UPDATE_WIDGET }
由于我无法在我的设备上重现,我不得不猜测解决方案是什么。
解决方案 #1
我可以传递将减少 UI 运行时间的值,而不是保存到 SharedPreferences 并从 SharedPreferences 读取。这个我可以马上改。
解决方案 #2
我应该调用一个广播并传递所有小部件 ID,而不是每个小部件 ID 循环并调用每个小部件 ID 的广播吗?它不会使 onReceive() 执行时间更长吗? (因为它必须更新所有小部件)。
解决方案 #2 是我不确定的。这种改变会有帮助吗?还是导致 ANR 更频繁地发生?
回答我自己的问题。
解决方案#1
通过意图传递数据值以避免从 SharedPreferences 加载数据 and/or 从 WorkerThread 加载 SharedPreferences 消除了 ANR 错误。
我已经尝试了解决方案 #2,但我不确定它是否有助于消除 ANR。
我有一个 JobScheduler 服务触发更新小部件 UI。
@Override
public boolean onStartJob(final JobParameters params) {
//Offloading work to a new thread.
new Thread(() -> {
try {
// Here we receive updated data and store to SharedPreferences
...
MyWidgetProvider.updateWidgets(getApplicationContext());
} catch (Exception e) {
Log.e(TAG, "onStartJob: " + e.getMessage());
} finally {
jobFinished(params, false);
}
}).start();
return true;
}
我的 AppWidgetProvider:
protected static void updateWidget(Context context) {
try {
ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class);
int[] appWidgetIds = AppWidgetManager.getInstance(context.getApplicationContext()).getAppWidgetIds(thisWidget);
if (appWidgetIds != null) {
if (appWidgetIds.length > 0) {
for (int appWidgetId : appWidgetIds) {
try {
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.setAction(UPDATE_WIDGET);
context.sendBroadcast(intent);
} catch (Exception e) {
}
}
}
}
} catch (Exception e) {
Log.e(TAG, "error" + e.getMessage());
}
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
try {
Bundle extras = intent.getExtras();
String action = intent.getAction();
if (extras != null && !TextUtils.isEmpty(action)) {
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
if (action.equals(UPDATE_WIDGET)) {
RemoteViews remoteViews = getRemoteView(context);
// Here read from the SharedPreferences and updates the remoteViews
....
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, remoteViews);
}
}
}
} catch (Exception e) {
Log.e(TAG, "onReceive() error: " + e.getMessage());
}
}
我在意图广播时遇到 ANR 错误 { act=.....UPDATE_WIDGET }
由于我无法在我的设备上重现,我不得不猜测解决方案是什么。
解决方案 #1 我可以传递将减少 UI 运行时间的值,而不是保存到 SharedPreferences 并从 SharedPreferences 读取。这个我可以马上改。
解决方案 #2 我应该调用一个广播并传递所有小部件 ID,而不是每个小部件 ID 循环并调用每个小部件 ID 的广播吗?它不会使 onReceive() 执行时间更长吗? (因为它必须更新所有小部件)。
解决方案 #2 是我不确定的。这种改变会有帮助吗?还是导致 ANR 更频繁地发生?
回答我自己的问题。
解决方案#1 通过意图传递数据值以避免从 SharedPreferences 加载数据 and/or 从 WorkerThread 加载 SharedPreferences 消除了 ANR 错误。
我已经尝试了解决方案 #2,但我不确定它是否有助于消除 ANR。