由于我使用AlarmManager
执行定期小部件更新,因此我需要确保onEnabled
& onDisabled
将可靠地运作。
然而,我意识到它们有时不会被触发。我不是唯一一个面临这个问题的人。
Android appWidgetProvider onEnabled never called on tablet
onDisabled
?因为我不希望在删除最后一个小部件之后仍然可以重复触发AlarmManager。 <receiver android:name="org.yccheok.MyAppWidgetProvider"
android:exported="true" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
public class MyAppWidgetProvider extends AppWidgetProvider {
private static PendingIntent createAlarmUpdatePendingIntent(Context context) {
Intent intent = new Intent(context, JStockAppWidgetProvider.class);
intent.setAction(JStockAppWidgetProvider.ALARM_UPDATE_ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
@Override
public void onEnabled(Context context)
{
super.onEnabled(context);
PendingIntent pendingIntent = createAlarmUpdatePendingIntent(context);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
int scanSpeed = JStockApplication.instance().getJStockOptions().getScanSpeed();
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + scanSpeed, scanSpeed, pendingIntent);
}
@Override
public void onDisabled(Context context)
{
super.onDisabled(context);
PendingIntent pendingIntent = createAlarmUpdatePendingIntent(context);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
答案 0 :(得分:1)
您可以在方法中检查当前正在运行的多个实例。
private boolean hasInstances(Context context) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(
new ComponentName(context, this.getClass()));
return (appWidgetIds.length > 0);
}
答案 1 :(得分:1)
我担心你误解了AppWidgetProvider
的方法。
onDeleted(Context context, int[] appWidgetIds)
Called in response to the ACTION_APPWIDGET_DELETED broadcast **when one or more** AppWidget instances have been deleted. Override this method to implement your own AppWidget functionality.
onDisabled(Context context)
Called in response to the ACTION_APPWIDGET_DISABLED broadcast, which is sent when the last AppWidget instance for this provider is deleted. Override this method to implement your own AppWidget functionality.
简而言之,如果您有两个或更多AppWidget实例,那么如果您当时删除其中任何一个,则只会调用特定小部件的onDeleted()
方法。
如果您只有一个AppWidget实例,那么如果您删除该时间onDesabled()
和onDeleted()
将会被调用。
因此,您必须将代码从onDesabled()
方法移至onDeleted()
方法,并且每次都会调用它。!
另外请注意,只会为第一个实例调用onEnabled()
,而不是为您创建的每个下一个实例调用。{/ p>
答案 2 :(得分:1)
根据我的理解,你只需要一个警报,我想所有的小部件都是一样的。因此,您的警报的想法是在服务上运行,而不是在小部件上运行。 您不应该在BroadcastReceiver上执行长时间的操作。
我们将使用onUpdate而不是onEnable(因为这个演示的设计)。然后我们得到一个新的小部件,我们可以执行该服务。
的AppWidgetProvider:
public class MyAppWidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
ComponentName thisWidget = new ComponentName(context, MyAppWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
Intent intent = new Intent(context.getApplicationContext(), JStockAppWidgetService.class);
intent.setAction(JStockAppWidgetService.ALARM_UPDATE_ACTION);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds);
context.startService(intent);
}
@Override
public void onDisabled(Context context)
{
super.onDisabled(context);
Intent intent = new Intent(context.getApplicationContext(), JStockAppWidgetService.class);
intent.setAction(JStockAppWidgetService.ALARM_STOP_ACTION);
// I kept this just in case you wanna keep running your alarm without widget. You can just stopService here too.
context.startService(intent);
}
}
这里的服务:
public class JStockAppWidgetService extends Service {
public static final String ALARM_UPDATE_ACTION = "ALARM_UPDATE_ACTION";
public static final String ALARM_STOP_ACTION = "ALARM_STOP_ACTION";
//delay to refresh your widget
private int delay = 10000; //10 secs
private Thread myThread;
@Override
public void onStart(Intent intent, int startId) {
final int[] allWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
//running your timeout while is not interrupted
while(!Thread.currentThread().isInterrupted()) {
//we need to back to GUI thread
handler.post(new Runnable() {
@Override
public void run() {
runInMyGuiThread(allWidgetIds);
}
});
//everybody needs to sleep sometime =p
Thread.sleep(delay);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
};
String action = intent.getAction();
if(action == ALARM_UPDATE_ACTION) {
if(myThread != null)
myThread.interrupt();
myThread = new Thread(runnable);
myThread.start();
} else if(action == ALARM_STOP_ACTION && myThread != null) {
myThread.interrupt();
}
}
//here you are in GUI thread with all your widgets id
public void runInMyGuiThread(int[] allWidgetIds) {
for(int widgetId : allWidgetIds){
//do what you want to update each widget
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
这只是一个小小的演示,您可以停止服务或让它在没有小部件的情况下继续运行,我会随身携带。
答案 3 :(得分:0)
我对以下情况感到困惑。
如果您已将小部件添加到锁定屏幕,然后通过将小部件添加到主屏幕进行测试,那么您永远不会看到onEnabled / onDisabled调用。原因是仍然添加了一个小部件 - 锁屏小部件。