Android實現(xiàn)一個定點提醒Service

接下來我要教大家如何實現(xiàn)一個APP后臺的定點提醒Service,功能包括輸入時間后長期在后臺運行,到達提醒時間時,發(fā)送Notification手機通知欄,提醒用戶。

實現(xiàn)原理:
將需要提醒的內(nèi)容及時間存入數(shù)據(jù)庫中,啟動Service時檢測數(shù)據(jù)庫是否有未提醒的時間,遍歷數(shù)據(jù)庫,從第一條最近的提醒時間開始,發(fā)送時間給手機系統(tǒng)鬧鐘,再定義一個廣播接收器,接收系統(tǒng)鬧鐘到點后的提醒。再發(fā)送Notification提醒用戶,需要的做的事。

步驟一#

創(chuàng)建SQLite數(shù)據(jù)庫


/**

*緩存數(shù)據(jù)的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) {

}

}

這里建了一個表,里面存入三個提醒時需要的信息,分別是時間,內(nèi)容,跟標(biāo)題。時間我采用的是毫秒型,所以存入的Long型。然后向數(shù)據(jù)庫添加我們需要提醒的時間跟內(nèi)容。

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();//獲取當(dāng)前時間,為了判斷添加時間是否已經(jīng)過時
 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數(shù)據(jù),或者自定義實體類,再傳入數(shù)據(jù),方法名請自行修改。if是判斷時間是否大于當(dāng)前時間,否則不添加。


步驟二#

創(chuàng)建Service,后臺處理提醒的數(shù)據(jù)。

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;    } //這里為了提高優(yōu)先級,選擇START_REDELIVER_INTENT 沒那么容易被內(nèi)存清理時殺死
@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()) { //遍歷數(shù)據(jù)庫的表,拿出一條,選擇最近的時間賦值,作為第一條提醒數(shù)據(jù)。
           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)});      //刪除已經(jīng)發(fā)送提醒的時間
    cursor.close();     //記得關(guān)閉游標(biāo),防止內(nèi)存泄漏  
   Intent startNotification = new Intent(this, AlarmReceiver.class);   //這里啟動的廣播,下一步會教大家設(shè)置
      startNotification.putExtra("title", title);    
      startNotification.putExtra("content", content); 
     am = (AlarmManager) getSystemService(ALARM_SERVICE);   //這里是系統(tǒng)鬧鐘的對象
     pi = PendingIntent.getBroadcast(this, 0, startNotification, PendingIntent.FLAG_UPDATE_CURRENT);     //設(shè)置事件
   if (time != null) {      
      am.set(AlarmManager.RTC_WAKEUP, time, pi);    //提交事件,發(fā)送給 廣播接收器
  } else {    
        //當(dāng)提醒時間為空的時候,關(guān)閉服務(wù),下次添加提醒時再開啟        
    stopService(new Intent(this, AlarmService.class));  
          }   
 }}

因為是長期運行在后臺,所以沒有與Activity進行綁定操作,這里做的就是讀取數(shù)據(jù)庫的數(shù)據(jù),然后一條一條啟動鬧鐘事件,到點后發(fā)送廣播給BroadcastReceiver,提醒完成后,再次回調(diào)服務(wù),開啟下一條提醒,直到?jīng)]有提醒時關(guān)閉。

一定要記得在AndroidManifest中配置Service,這里我取名為AlarmService。優(yōu)先級設(shè)置最大,防止被內(nèi)存回收銷毀。

Service配置.png

步驟三#

設(shè)置BroadcastReceiver廣播接收器,接收系統(tǒng)鬧鐘發(fā)送過來的廣播。實現(xiàn)提醒業(yè)務(wù),這里我采用的是Notification通知,可根據(jù)自己需求更改。

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) { 
//此處接收鬧鐘時間發(fā)送過來的廣播信息,為了方便設(shè)置提醒內(nèi)容
        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);  //回調(diào)Service,同一個Service只會啟動一個,所以直接再次啟動Service,會重置開啟新的提醒,
  }    /**     * 發(fā)送通知     */   
 private void showNormal(Context context) { 
        Intent intent = new Intent(context, BianQianDataActivity.class);//這里是點擊Notification 跳轉(zhuǎn)的界面,可以自己選擇
        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)     //設(shè)置通知圖標(biāo)。
                .setTicker(content)        //通知時在狀態(tài)欄顯示的通知內(nèi)容
                .setContentInfo("便簽提醒")        //內(nèi)容信息       
                .setContentTitle(title)        //設(shè)置通知標(biāo)題。
                .setContentText(content)        //設(shè)置通知內(nèi)容。
                .setAutoCancel(true)                //點擊通知后通知消失
                .setDefaults(Notification.DEFAULT_ALL)        //設(shè)置系統(tǒng)默認(rèn)的通知音樂、振動、LED等。
                .setContentIntent(pi) 
               .build();
        manager.notify(NOTIFICATION_ID_1, notification);
    }}

到這里,一個基本的定點提醒服務(wù)就完成了,可以根據(jù)需求,完成提醒后的業(yè)務(wù)邏輯,比如直接彈出應(yīng)用等。在存入提醒的時間后,啟動服務(wù)就行,另外Receiver和Service都需要在配置文件中注冊,不可忘記。

擴展#

另外還可以根據(jù)個人需求,設(shè)置開機自啟動該服務(wù),只需要監(jiān)聽系統(tǒng)廣播即可,我建議是開啟自啟動的,否則關(guān)機后,有的提醒將無法完成。

//開機廣播接收
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狀態(tài)   
         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);   
         }     
   }
    }}

在這里,我還實現(xiàn)了檢測服務(wù)是否被關(guān)閉,每五分鐘會監(jiān)聽到一個系統(tǒng)廣播,如果服務(wù)被關(guān)閉,就會再次啟動。當(dāng)然,這個定點提醒做到這里,一般的情況下已經(jīng)有點死皮賴臉難以被殺死,你如果還想更流氓一點,就去看一下守護進程的相關(guān)知識,
鏈接
守護進程相關(guān)知識

結(jié)語#

剛開始用簡書寫文章,還不太習(xí)慣,代碼還是自己一行一行的排版,不太好看,大家如果有什么問題,或者我代碼中有什么錯誤,歡迎大家指出,定為修改,不懂的也可以提問,,謝謝!

本文為原創(chuàng)文章,未經(jīng)允許不得轉(zhuǎn)載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,829評論 18 139
  • 原文出處: http://www.androidchina.net/6174.html Notification在...
    木木00閱讀 12,370評論 3 32
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,761評論 25 708
  • HandlerThread是一個Android 已封裝好的輕量級異步類。HandlerThread本質(zhì)上是一個線程...
    kjy_112233閱讀 1,322評論 0 9
  • 我以前在學(xué)習(xí)安卓開發(fā)時曾經(jīng)用到過Bmob后端云作為后端數(shù)據(jù)存儲于查詢,因此微信小程序出來之后我也想用它作為微信小程...
    呂周坤閱讀 11,044評論 6 11