Обновление виджета приложения с помощью AlarmManager - PullRequest
10 голосов
/ 29 марта 2011

Я пытаюсь обновить виджет чаще, чем 30-минутное ограничение, наложенное 1.6docs. Прочитав почти каждый пост в SO, а также документы для разработчиков и различные другие источники, я подумал, что дошел до того, что смогу его реализовать. И вот, я попробовал, и не получилось. С тех пор я перебрал еще больше форумов и решений и, похоже, не могу его обновить.

У меня есть класс обновления, который устанавливает AlarmManager:

public class Update extends Service{

    @Override
    public void onStart(Intent intent, int startId) {
          String currentTemp = Battery.outputTemp;
          String currentLevel = Battery.outputLevel;
          String currentCard = Battery.outputCard;
          String currentInternal = Battery.memory;
          String currentRam = String.valueOf(Battery.outputRam).substring(0, 3) + "MB";

          // Change the text in the widget
          RemoteViews updateViews = new RemoteViews( 
          this.getPackageName(), R.layout.main);
          //update temp
          updateViews.setTextViewText(R.id.batteryTemp, currentTemp); 
          //update %
          updateViews.setTextViewText(R.id.batteryLevel, currentLevel);     
          //update level
          updateViews.setTextViewText(R.id.sdCard, currentCard);
          //update internal memory
          updateViews.setTextViewText(R.id.internal, currentInternal);
          //update ram
          updateViews.setTextViewText(R.id.ram, currentRam);

          ComponentName thisWidget = new ComponentName(this, Widget.class);
          AppWidgetManager manager = AppWidgetManager.getInstance(this);
          manager.updateAppWidget(thisWidget, updateViews);

    }
    @Override
    public IBinder onBind(Intent intent) {
        // no need to bind
        return null;
    }

}

Это вызвало частое срабатывание моего onReceive в моем классе виджетов (у меня есть тост, чтобы увидеть, когда он срабатывает), но у него нет намерения (тост предназначен для отображения этого по мере их получения, но он пустой).

Я не могу понять это (я относительный новичок-2 месяца медленной разработки для Android) и ценю любые идеи, которые у вас есть, ребята.

вот мой класс виджетов для справки:

    public class Widget extends AppWidgetProvider {


    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {

        AlarmManager alarmManager;
        Intent intent = new Intent(context, Update.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarmManager = (AlarmManager) context
                .getSystemService(Context.ALARM_SERVICE);
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(System.currentTimeMillis());
        cal.add(Calendar.SECOND, 10);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal
                .getTimeInMillis(), 5 * 1000, pendingIntent);

        String currentTemp = Battery.outputTemp;
        String currentLevel = Battery.outputLevel;
        String currentCard = Battery.outputCard;
        String currentInternal = Battery.memory;
        String currentRam = String.valueOf(Battery.outputRam).substring(0, 3)
                + "MB";

        // Change the text in the widget
        RemoteViews updateViews = new RemoteViews(context.getPackageName(),
                R.layout.main);
        // update temp
        updateViews.setTextViewText(R.id.batteryTemp, currentTemp);
        appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
        // update %
        updateViews.setTextViewText(R.id.batteryLevel, currentLevel);
        appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
        // update level
        updateViews.setTextViewText(R.id.sdCard, currentCard);
        appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
        // update internal memory
        updateViews.setTextViewText(R.id.internal, currentInternal);
        appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
        // update ram
        updateViews.setTextViewText(R.id.ram, currentRam);
        appWidgetManager.updateAppWidget(appWidgetIds, updateViews);
        super.onUpdate(context, appWidgetManager, appWidgetIds);

    }

    public void onReceive(Context context, Intent intent) {

        super.onReceive(context, intent);
        Toast
                .makeText(context, intent.getAction() + context,
                        Toast.LENGTH_LONG).show();
        Bundle extras = intent.getExtras();
        if (extras != null) {
            AppWidgetManager appWidgetManager = AppWidgetManager
                    .getInstance(context);
            ComponentName thisAppWidget = new ComponentName(context
                    .getPackageName(), Widget.class.getName());
            int[] appWidgetIds = appWidgetManager
                    .getAppWidgetIds(thisAppWidget);

            onUpdate(context, appWidgetManager, appWidgetIds);
        }

    }
}

Ответы [ 3 ]

20 голосов
/ 14 января 2013

Это моё решение, как автоматически обновлять виджет чаще, чем за 30 минут. Я использую AlarmManager. Прежде чем использовать AlarmManager для обновления виджета приложения, убедитесь, что вы знаете, что делаете, потому что этот метод может разрядить аккумулятор устройства.

Подробнее об обновлении виджета в Android doc - особенно о параметре updatePeriodMillis.

Это часть моего Manifest.xml. Я определяю настраиваемое действие AUTO_UPDATE.

<receiver android:name=".appwidget.AppWidget" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <intent-filter>
        <action android:name="AUTO_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" />
</receiver>

Это часть моего AppWidget.java. В методе onReceive я обрабатываю свое настраиваемое действие AUTO_UPDATE. В методах onEnabled и onDisabled я запускаю / останавливаю сигнал тревоги.

public class AppWidget extends AppWidgetProvider
{
    public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";

    @Override
    public void onReceive(Context context, Intent intent)
    {
        super.onReceive(context, intent);

        if(intent.getAction().equals(ACTION_AUTO_UPDATE))
        {
            // DO SOMETHING
        }

        ...
    }

    @Override
    public void onEnabled(Context context)
    {
        // start alarm
        AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
        appWidgetAlarm.startAlarm();
    }

    @Override
    public void onDisabled(Context context)
    {
        // stop alarm only if all widgets have been disabled
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        ComponentName thisAppWidgetComponentName = new ComponentName(context.getPackageName(),getClass().getName());
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidgetComponentName);
        if (appWidgetIds.length == 0) {
            // stop alarm
            AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
            appWidgetAlarm.stopAlarm();
    }

    }

    ...
}

Это мой AppWidgetAlarm.java, который запускает / останавливает тревогу. Диспетчер аварийных сигналов отправляет трансляцию в AppWidget.

public class AppWidgetAlarm
{
    private final int ALARM_ID = 0;
    private final int INTERVAL_MILLIS = 10000;

    private Context mContext;


    public AppWidgetAlarm(Context context)
    {
        mContext = context;
    }


    public void startAlarm()
    {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS);

        Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        // RTC does not wake the device up
        alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), INTERVAL_MILLIS, pendingIntent);
    }


    public void stopAlarm()
    {
        Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
    }
}
12 голосов
/ 29 марта 2011

У меня есть класс обновления, который устанавливает AlarmManager:

Нет, нет. AlarmManager нигде в коде не появляется.

У вас до есть ссылка на AlarmManager во втором фрагменте кода. Проблемы там включают в себя:

  • Вы устанавливаете новый повторяющийся сигнал каждый раз, когда обновляется виджет приложения

  • Вы устанавливаете 5-секундную частоту для тревоги, что является абсолютным безумием

  • Вы устанавливаете 5-секундную частоту для _WAKEUP сигнала тревоги, что, я думаю, является основанием для вашего ареста в некоторых юрисдикциях

  • У вас есть бессмысленный метод onReceive(), даже игнорируя временный Toast

  • Вы предполагаете, что строка Intent в вашем Toast будет иметь строку действия, но вы не указываете строку действия при создании Intent, который вы вставили в PendingIntent для будильника

  • Ваш код относится к тому, что, как я предполагаю, является статическими членами данных в классе Battery, но вполне вероятно, что все они пустые / нулевые ... или, по крайней мере, они были бы, если бы у вас был вменяемый частота по тревоге

1 голос
/ 01 марта 2019

Спасибо за этот пример - у меня также были проблемы с использованием более поздней версии Android.

Этот пост заставил меня работать: случай с виджетом, который не работает (см. Ответ Ларри Шифера).

Подставляя это из кода выше:

Intent alarmIntent = new Intent(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);

с этим из ссылки:

Intent alarmIntent=new Intent(mContext, MyWidget.class);
alarmIntent.setAction(AppWidget.ACTION_AUTO_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);

сделал работу.

...