Android Service,AlarmManager組合實現定時任務踩的坑


做項目時遇到一個場景:app需要定時訪問后台,感知獲取登錄用戶有沒有最新的消息。

我采用了定義一個Service,在onStartCommand()方法中請求后台獲取最新消息,接着創建一個AlarmManager來延時發送廣播,再定義一個廣播接收器,接收到一個廣播后,接收器觸發startService( ),這時service的onStartCommand再次被觸發,就再次請求獲取最新消息,繼續發送廣播,如此往復。

Created with Raphaël 2.1.0 MyNewTaskService MyNewTaskService MyNewTaskReceiver MyNewTaskReceiver AlarmManager(5s)|param:Intent->userId intent.getStringExtra("userId") startService(Intent->userId) 通過userId訪問網絡

用戶名userId是登錄成功后就能得到的。在登錄成功進入主界面后,並立即啟動MyNewTaskService

MyNewTaskService的主要業務邏輯代碼如下:

    public int onStartCommand(Intent intent, int flags, int startId) {
mRealm = Realm.getDefaultInstance();
mUserDao = new UserDao(mRealm);//獲取當前登錄用戶id
mTaskTimeDao = new TaskTimeDao(mRealm);
if(intent!=null){
userId = intent.getStringExtra("userId");
}else{
userId = mUserDao.getUserInfo().getUserId();//realm也保存了用戶信息,但不一定每次都能獲取到
}
if(null!=userId){
//...做一些事情,比如訪問網絡獲取最新消息
//設置定時操作
AlarmManager am= (AlarmManager)getSystemService(ALARM_SERVICE);
//1分鍾請求一次更新
int elapseTime = 1*60*1000;
long interval = SystemClock.elapsedRealtime()+elapseTime;
//傳遞userId參數給MyNewTaskReceiver,為了到時候回傳回來
Intent i = new Intent(this,MyNewTaskReceiver.class);
i.putExtra("userId",userId);
PendingIntent pi = PendingIntent.getBroadcast(this,0,i,0);
am.set(AlarmManager.ELAPSED_REALTIME,interval,pi);
}
return super.onStartCommand(intent, flags, startId);
}

下面是MyNewTaskReceiver類

public class MyNewTaskReceiver extends BroadcastReceiver{    
@Override
public void onReceive(Context context, Intent intent) {
Intent i= new Intent(context, MyNewTaskService.class);
i.putExtra("userId",intent.getStringExtra("userId"));
Log.i("user",intent.getStringExtra("userId"));
context.startService(i);
//每1分鍾將接收到一次廣播,這時觸發service的onStartCommand()執行需要的重復操作
}
}

但是app測試時發現,當第一次登錄進去后,例如此時用戶名是 ‘zs’ ,這是后台可以每1分鍾接收到’zs’的最新的消息。然而,現在’zs’退出登錄,用’ls’賬號登錄,這時后台返回的消息仍然還是’zs’的,而不是’ls’的。

后來發現,每次第一個登錄的用戶登陸后,后面不管任何其他用戶再次登錄同一台手機,后台返回的都是第一個用戶的信息。因為App設計的時第一次登錄成功后,Service會一直在后台執行。所以懷疑第一次創建Service后,Service所持有的userId並沒有更新。

經過調試,發現,MyNewTaskReceiver接收的Intent中獲取的userId全都是第一次登錄用戶的id。猜想可能發送廣播時傳入的參數有問題。

經過查閱安卓API發現,定時器AlarmManager初始化時傳入的PendingIntent的構造函數的第四個參數需要一個Flag常量。
這里寫圖片描述

之前我傳入的是0。沒有作用。

當改為 FLAG_UPDATE_CURRENT 時,每次發送的廣播傳遞的Intent就能更新了。
這里寫圖片描述

將onStartCommand()方法的這一行改為

 PendingIntent pi = PendingIntent.getBroadcast(this,0,i,0);
PendingIntent pi = PendingIntent.getBroadcast(this,0,i,FLAG_UPDATE_CURRENT);

這時不管那個用戶登錄,后台都可以定時返回當前用戶的消息了。

總結&注意:

1 該示例的后台Service在用戶關閉app后並沒有stop。如果stop,相信不會有這種Bug產生。因為定時任務是依附於Service存在的。

2 曾經嘗試在主Activity的onDestory()中調用StopService()方法讓app關閉后service也結束運行,沒有成功。如果service在app關閉后也停止運行,相信不會有這種bug產生。

3 app經過多方面測試才能完善。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com 联系我们: