Android实现一个定点提醒Service

接下来我要教大家如何实现一个APP后台的定点提醒Service,功能包括输入时间后长期在后台运行,到达提醒时间时,发送Notification手机通知栏,提醒用户。

实现原理:
将需要提醒的内容及时间存入数据库中,启动Service时检测数据库是否有未提醒的时间,遍历数据库,从第一条最近的提醒时间开始,发送时间给手机系统闹钟,再定义一个广播接收器,接收系统闹钟到点后的提醒。再发送Notification提醒用户,需要的做的事。

步骤一#

创建SQLite数据库


/**

*缓存数据的SQLite

* 2016/9/27.

*/

public class AppSQLiteData extends SQLiteOpenHelper {

public static String Remind_data="create table Remind_data("

+"id integer primary key autoincrement, "

+"remindTime long,"

+"content text,"

+"title text"+")";

private Context mContext;

public AppSQLiteData(Context context,String name,SQLiteDatabase.CursorFactory factory, intversion) {

super(context,name,factory,version);

mContext= context;

}

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(Remind_data);

}

@Override

public void onUpgrade(SQLiteDatabase db, intoldVersion, intnewVersion) {

}

}

这里建了一个表,里面存入三个提醒时需要的信息,分别是时间,内容,跟标题。时间我采用的是毫秒型,所以存入的Long型。然后向数据库添加我们需要提醒的时间跟内容。

private AppSQLiteData mRemindSQL;
public void AddData(final Context context, final List<RemindList> data) {
//将获取到的便签列表时间缓存入SQL
new Thread(new Runnable() {
@Override
public void run() {   
 Calendar c = Calendar.getInstance();//获取当前时间,为了判断添加时间是否已经过时
 mRemindSQL= new AppSQLiteData(context, "Remind.db", null, 1);
 mRemindSQL.getWritableDatabase();
 SQLiteDatabase db = mRemindSQL.getWritableDatabase();
 ContentValues values = new ContentValues();
 for (int i = 0; i < data.size() - 1; i++) {
  if (!data.get(i).getRemindTime().equals("") && Long.parseLong(data.get(i).getRemindTime()) > c.getTimeInMillis()) {
    values.put("remindTime", Long.parseLong(data.get(i).getRemindTime()));
    values.put("title", data.get(i).getTitle());
    values.put("content", data.get(i).getLevel());
db.insert("Remind_data", null, values);
     }
values.clear();
  }}).start();

需要注意的是我这里的List是接收的一个实体类,你们可以手动添加data数据,或者自定义实体类,再传入数据,方法名请自行修改。if是判断时间是否大于当前时间,否则不添加。


步骤二#

创建Service,后台处理提醒的数据。

public class AlarmService extends Service {  
  private AlarmManager am;  
  private PendingIntent pi;  
  private Long time;   
  private String title; 
  private String content;
  private AppSQLiteData mRemindSQL;    
@Nullable    
@Override    
public IBinder onBind(Intent intent) {  
      return null; 
   }    
@Override    
public void onCreate() {     
   super.onCreate();  
  }    
@Override    
public int onStartCommand(Intent intent, int flags, int startId) { 
       getAlarmTime();
       return START_REDELIVER_INTENT;    } //这里为了提高优先级,选择START_REDELIVER_INTENT 没那么容易被内存清理时杀死
@Override    
public void onDestroy() {    
    super.onDestroy();    
}    
public void getAlarmTime() {  
      mRemindSQL= new AppSQLiteData(this,"Remind.db", null, 1);  
      SQLiteDatabase db = mRemindSQL.getWritableDatabase();   
      Cursor cursor = db.query("Remind_data", null, null, null, null, null, null);        
      if (cursor.moveToFirst()) { //遍历数据库的表,拿出一条,选择最近的时间赋值,作为第一条提醒数据。
           time = cursor.getLong(cursor.getColumnIndex("remindTime")); 
           title = cursor.getString(cursor.getColumnIndex("title")); 
           content = cursor.getString(cursor.getColumnIndex("content"));   
         do {   if (time > cursor.getLong(cursor.getColumnIndex("remindTime"))) {   
                 time = cursor.getLong(cursor.getColumnIndex("remindTime"));  
                 title = cursor.getString(cursor.getColumnIndex("title"));   
                 content = cursor.getString(cursor.getColumnIndex("content")); 
                            }    
             } while (cursor.moveToNext());      
          } else {          
          time = null;    
              }     
    db.delete("Remind_data", "remindTime=?", new String[]{String.valueOf(time)});      //删除已经发送提醒的时间
    cursor.close();     //记得关闭游标,防止内存泄漏  
   Intent startNotification = new Intent(this, AlarmReceiver.class);   //这里启动的广播,下一步会教大家设置
      startNotification.putExtra("title", title);    
      startNotification.putExtra("content", content); 
     am = (AlarmManager) getSystemService(ALARM_SERVICE);   //这里是系统闹钟的对象
     pi = PendingIntent.getBroadcast(this, 0, startNotification, PendingIntent.FLAG_UPDATE_CURRENT);     //设置事件
   if (time != null) {      
      am.set(AlarmManager.RTC_WAKEUP, time, pi);    //提交事件,发送给 广播接收器
  } else {    
        //当提醒时间为空的时候,关闭服务,下次添加提醒时再开启        
    stopService(new Intent(this, AlarmService.class));  
          }   
 }}

因为是长期运行在后台,所以没有与Activity进行绑定操作,这里做的就是读取数据库的数据,然后一条一条启动闹钟事件,到点后发送广播给BroadcastReceiver,提醒完成后,再次回调服务,开启下一条提醒,直到没有提醒时关闭。

一定要记得在AndroidManifest中配置Service,这里我取名为AlarmService。优先级设置最大,防止被内存回收销毁。

Service配置.png

步骤三#

设置BroadcastReceiver广播接收器,接收系统闹钟发送过来的广播。实现提醒业务,这里我采用的是Notification通知,可根据自己需求更改。

public class AlarmReceiver extends BroadcastReceiver { 
   private NotificationManager manager; 
   private static final int NOTIFICATION_ID_1 = 0x00113;  
   private String title;
   private String content = "提醒的时间到啦,快看看你要做的事..."; 
 @Override
  public void onReceive(Context context, Intent intent) { 
//此处接收闹钟时间发送过来的广播信息,为了方便设置提醒内容
        title = intent.getStringExtra("title"); 
        content = intent.getStringExtra("content ");
        showNormal(context);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClass(context, AlarmService.class); 
        context.startService(intent);  //回调Service,同一个Service只会启动一个,所以直接再次启动Service,会重置开启新的提醒,
  }    /**     * 发送通知     */   
 private void showNormal(Context context) { 
        Intent intent = new Intent(context, BianQianDataActivity.class);//这里是点击Notification 跳转的界面,可以自己选择
        PendingIntent pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 
        Notification notification = new NotificationCompat.Builder(context)
                .setSmallIcon(R.mipmap.daka)     //设置通知图标。
                .setTicker(content)        //通知时在状态栏显示的通知内容
                .setContentInfo("便签提醒")        //内容信息       
                .setContentTitle(title)        //设置通知标题。
                .setContentText(content)        //设置通知内容。
                .setAutoCancel(true)                //点击通知后通知消失
                .setDefaults(Notification.DEFAULT_ALL)        //设置系统默认的通知音乐、振动、LED等。
                .setContentIntent(pi) 
               .build();
        manager.notify(NOTIFICATION_ID_1, notification);
    }}

到这里,一个基本的定点提醒服务就完成了,可以根据需求,完成提醒后的业务逻辑,比如直接弹出应用等。在存入提醒的时间后,启动服务就行,另外Receiver和Service都需要在配置文件中注册,不可忘记。

扩展#

另外还可以根据个人需求,设置开机自启动该服务,只需要监听系统广播即可,我建议是开启自启动的,否则关机后,有的提醒将无法完成。

//开机广播接收
public class BootReceiver extends BroadcastReceiver { 
   public BootReceiver() {    }
    private final String ACTION = "android.intent.action.BOOT_COMPLETED"; 
   @Override 
   public void onReceive(Context context, Intent intent) {  
      if (intent.getAction().equals(ACTION)) { 
           Intent inten2 = new Intent(context, AlarmService.class); 
           context.startService(inten2);
        }  
            boolean isServiceRunning = false;
        if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) { 
           //检查Service状态   
         ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);  
          for (ActivityManager.RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE)) {  
              if("so.xxxx.xxxxService".equals(service.service.getClassName()))                {      
              isServiceRunning = true;        
        }         
   }      
      if (!isServiceRunning) {    
    Intent i = new Intent(context, AlarmService.class); 
       context.startService(i);   
         }     
   }
    }}

在这里,我还实现了检测服务是否被关闭,每五分钟会监听到一个系统广播,如果服务被关闭,就会再次启动。当然,这个定点提醒做到这里,一般的情况下已经有点死皮赖脸难以被杀死,你如果还想更流氓一点,就去看一下守护进程的相关知识,
链接
守护进程相关知识

结语#

刚开始用简书写文章,还不太习惯,代码还是自己一行一行的排版,不太好看,大家如果有什么问题,或者我代码中有什么错误,欢迎大家指出,定为修改,不懂的也可以提问,,谢谢!

本文为原创文章,未经允许不得转载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容