Android AlarmManager在重启后继续/从RecentTaskManager中删除

时间:2016-11-15 16:57:10

标签: android notifications alarmmanager intentservice

我想在用户预设之前使用AlarmManager从服务器向用户发送通知。代码如下:

MainActivity:

df.directives.directive('dfLikeProduct', function($window) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      // Props
      var $element = $(element);
      var $amount = $element.prev();
      var url = $element.attr('href');

      // Methods
      var likeProduct = function(){
        $.post(url, function(data){ 
          if (data == 1) {
            element.removeClass('unlike').addClass('active like');
            var num = parseFloat($amount.text());
            $amount.text(++num);
          } else if (data == -1) {
            element.removeClass('active like').addClass('unlike');
            var num = parseFloat($amount.text());
            $amount.text(--num);
          }
        }).fail(function(){
          $window.location.href = '/login';
        });
      }


      // Listeners
      $element.on('click', function(e){
        e.preventDefault();
        console.log(url);
        //likeProduct();
      });


      // Init

    }
  };
});

ParseService:

public void set_Retrival_then_notifcation_Alarm(Context context, int year, int month, int day, int hour, int min, int sec) 
    {
        Calendar updateTime = Calendar.getInstance();
        updateTime.setTimeZone(TimeZone.getDefault());
        updateTime.set(Calendar.YEAR, year);
        updateTime.set(Calendar.MONTH, month-1);
        updateTime.set(Calendar.DATE, day);
        updateTime.set(Calendar.HOUR_OF_DAY, hour);
        updateTime.set(Calendar.MINUTE, min);
        updateTime.set(Calendar.SECOND, sec);
        Intent downloader = new Intent(context, AlarmBroadcastReceiver.class);
        downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);           
        alarmManager.set(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), pendingIntent);                        
    }

AlarmBroadcastManager

public class ParseService extends IntentService 
{
    static String Parse_AppID = "abc";  
    static String Parse_ClientKey = "abckey";
    String notification_next_price = "";
    String notification_next_date = "";
    SharedPreferences settings;

    public class LocalBinder extends Binder 
    {
        public ParseService getService() 
        {
            return ParseService.this;
        }
    }

    public ParseService() 
    {
        super("ParseService");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent,flags,startId);
        return START_STICKY ;
    }

    @Override
    protected void onHandleIntent(Intent intent) 
    {
        Log.d("MyService", "About to execute MyTask");
        new MyTask().execute();
    }

    private class MyTask extends AsyncTask<String, Void, Boolean> 
    {
        @Override
        protected Boolean doInBackground(String... strings) 
        {
            Log.d("MyService - MyTask", "Calling doInBackground within MyTask");
            initParse(ParseService.this);
            get_notification_info(ParseService.this);
            return false;
        }
    }

    private void sendNotification(Context context, String title, String content) 
    {
        Log.d("MyService - MyTask", "A - sendNotification");
        settings = context.getSharedPreferences("MyApp",0);
        boolean notify_is_on = settings.getBoolean("notify_is_on", true);
        int saved_amount = settings.getInt("saved_amount", 800);

        NumberFormat numberFormat = NumberFormat.getInstance();
        int k = 0;
        try
        {
            k = numberFormat.parse(notification_next_price).intValue();
            if (notify_is_on && (k >= (saved_amount*10000)))
            {
                setNotificationContent(context, k, ""+title, content + "");
            }
            else
            {
                Toast.makeText(getApplicationContext(), "No need notification", Toast.LENGTH_SHORT).show();
            }
        }
        catch (Exception ex)
        {
            setNotificationContent(context, k, "Title2", "Content2");
        }
    } 

    public void setNotificationContent(Context context, int k, String title, String content)
    {
        Intent notificationIntent = new Intent(context, CurrentResult.class);
        PendingIntent pi = PendingIntent.getActivity(context, 0, notificationIntent, 0);
        Notification noti = new Notification.Builder(context)
            .setTicker("Hello")
            .setSmallIcon(R.drawable.b06)
            .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher))
            .setAutoCancel(true)
            .setOngoing(true) 
            .setOnlyAlertOnce(true)
            .setContentTitle(""+title)
            .setContentText(""+content)
            .setContentIntent(pi)
         .build();

        startForeground(1337, noti);

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0, noti);

        stopSelf();
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }

    public void initParse(Context context) 
    {
        try 
        {
            ...connection to Parse.com
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

    public void get_notification_info(Context context)
    {       
        ParseQuery<ParseObject> query = ParseQuery.getQuery("Record_db");
        //....getting records from server
        sendNotification(ParseService.this, ""+notification_next_price, ""+notification_next_date);
                    }                   
                } 
                else 
                {
                    Toast.makeText(getApplicationContext(), "Getting server content error", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

清单:

public class AlarmBroadcastReceiver extends BroadcastReceiver 
{
    public AlarmBroadcastReceiver () {
    }

    @Override
     public void onReceive(Context context, Intent intent) 
     {
         Intent dailyUpdater = new Intent(context, ParseService.class); 
         context.startService(dailyUpdater);
         Log.d("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive");
     }
}

问题:

当应用程序位于最近的任务列表中时,从服务器获取记录并发送到通知正常工作。

但是,如果从最近的任务列表中手动删除应用程序,则会取消alarmManager,从而取消通知,从而不会收到任何通知。

我使用Google搜索,大部分解决方案是在<service android:name="com.abc.abc.ParseService" android:enabled="true" android:exported="true" /> <receiver android:name="com.abc.abc.AlarmBroadcastReceiver" android:enabled="true" android:exported="true" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> 中返回START_STICKY,在Manifest中注册,但我尝试过没有成功。

你能帮忙看看问题是什么吗?为什么在从最近的任务列表中手动删除应用程序后无法重新启动通知?是否有任何示例使onStartCommand在用户的预设时间内正在工作?

谢谢!

4 个答案:

答案 0 :(得分:4)

  • 您需要将已注册的警报存储在本地数据库中
  • 然后创建一个启动完成的接收器
    • 在此接收器中加载所有警报并再次注册
  • 在AlarmBroadcastReceiver类中从db
  • 中删除此警报

多数民众赞成

答案 1 :(得分:3)

使用GcmListenerService代替AlarmManager,即使您的应用已从任务管理器移除GcmListenerService

,也会收到通知

答案 2 :(得分:2)

我已修改

set_Retrival_then_notifcation_Alarm 

如下进行测试。在当前时间添加30秒并设置警报。 同时从最近的任务中杀死应用程序进行测试。

 Calendar cur_cal = Calendar.getInstance();
        cur_cal.setTimeInMillis(System.currentTimeMillis());
        cur_cal.add(Calendar.SECOND, 30);
        Log.d("Testing", "Calender Set time:"+cur_cal.getTime());
        Intent intent = new Intent(this, ParseService.class);
        Log.d("Testing", "Intent created");
        PendingIntent pi = PendingIntent.getService(this, 0, intent, 0);
        AlarmManager alarm_manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        alarm_manager.set(AlarmManager.RTC, cur_cal.getTimeInMillis(), pi);
        Log.d("Testing", "alarm manager set");
        Toast.makeText(this, "ServiceClass.onCreate()", Toast.LENGTH_LONG).show();

您可以从PendingIntent触发服务。如果用户从最近的任务中清除应用程序,这将解决问题。

正如Hossam Alaa在 link 所说,你可以为引导问题做到这一点。 你也不需要在IntentService中使用AsyncTask。它有一个工作线程。

ParseService的示例(根据您的需要进行修改,目前它将等待5000毫秒并触发通知)。

public class ParseService extends IntentService {


public ParseService() {
    super("ParseService");
}


@Override
protected void onHandleIntent(Intent intent) {
    if (intent != null) {
        try {
            Thread.sleep(5000);
            setNotificationContent("HELLO","THERE");
            //stopSelf();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public void setNotificationContent( String title, String content)
{
    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    Notification noti = new Notification.Builder(this)
            .setTicker("Hello")
            .setAutoCancel(true)
            .setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setOnlyAlertOnce(true)
            .setContentTitle(""+title)
            .setContentText(""+content)
            .setContentIntent(pi).build();

    startForeground(1337, noti);

    NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, noti);


}
}

答案 3 :(得分:0)

只有在您的应用被移除或禁用时(在应用管理器中),警报才会被删除,它们肯定会在正常重启或暂停后继续存在。

但我不确定您的清单是否设置正确: 警报正在向'AlarmBroadcastReceiver.class&#39;发送广播。如果app在特定时刻还活着,它会响应。

我建议使用闹钟广播自定义动作并将其注册到接收器中。

在清单中添加到您的接收器:

<intent-filter>
    <action android:name="com.abc.abc.action.downloader" />
</intent-filter>

并使用另一个警告意图,如:

Intent downloader = new Intent(context, "com.abc.abc.action.downloader");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);