基本的に、このコードがどのように機能するかは...最初の計算から始まり、X分後にalarmmanagerでサービスを開始し、終了計算を取得して2つの違いを決定します。各アラームの終わりに、新しいアラームが同じ時間間隔で設定されます。時間間隔を 10 分に設定すると、アラームがまったく鳴りません。
これは、このアルゴリズムを作成するためのさまざまな方法で何日も対処しようとしてきた問題であるため、電話の CPU がスリープ状態になることと関係があると思います。
これがなぜなのかについての手がかりがあれば、これは私のプログラムの機能にとって非常に重要であるため、どんな助けでも大歓迎です。補足として、このコードは最大 5 分間の短い間隔で問題なく実行されます。10 を接続するとすぐに、何も得られませんでした。
私のサービスから
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Set return value
int retVal = START_NOT_STICKY;
if (intent != null) {
System.out.println("Service Thread: " + Thread.currentThread().getName());
// Set up context reference for getObject
self = this;
// Set up global intent reference
theIntent = intent;
// Get data
getData();
// Enter foreground state
String title = "The service has been started...";
String subject = "Service is running.";
String body = "Monitoring your battery usage...";
Notification notification = new Notification(R.drawable.theicon, title,
System.currentTimeMillis());
if (notificationSounds)
notification.defaults |= Notification.DEFAULT_SOUND;
else
notification.sound = null;
Intent notificationIntent = new Intent(this, MainActivity3.class);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, subject, body, pendIntent);
startForeground(1500, notification);
// Calculate wait time (convert from minutes to ms)
int waitTime = interval * 60000;
// int waitTime = 15000; // Debug 15 second wait
// Get initial battery
int initialBatt = getBatteryPercent();
// Debug
System.out.println("Initial battery percent: " + initialBatt);
// Get current time
Calendar c = Calendar.getInstance();
Date dateNow = c.getTime();
long timeNow = dateNow.getTime(); // Time in MS
// Set up alarm manager to wait and then execute next step
AlarmManager AM = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
svcIntent1 = new Intent(Service.getObject(), AlarmReceiver.class);
svcIntent1.putExtra("timeToUse", timeToUse);
svcIntent1.putExtra("interval", interval);
svcIntent1.putExtra("rawTime", rawTime);
svcIntent1.putExtra("initialBatt", initialBatt);
svcIntent1.putExtra("sounds", notificationSounds);
pendingIntent = PendingIntent.getBroadcast(Service.getObject(), 0, svcIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
// Set up the next alarm
System.out.println("The current time is " + dateNow.
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd hh:mm:ss a");
Toast.makeText(this, "The current time is " + sdf.format(dateNow), Toast.LENGTH_LONG).show();
Date n = new Date();
n.setTime(timeNow+waitTime);
System.out.println("Next calculation will complete at " + sdf.format(n));
Toast.makeText(this, "Next calculation will complete at " + sdf.format(n), Toast.LENGTH_LONG).show();
AM.setExact(AlarmManager.RTC_WAKEUP, timeNow + waitTime, pendingIntent);
}
return retVal;
}
ブロードキャスト レシーバー クラス内の onReceive
@Override
public void onReceive(Context c, Intent intent) {
if(intent != null){
// Get app context
context = Service.getObject();
Toast.makeText(context, "Alarm broadcast received.", Toast.LENGTH_SHORT).show();
// Set up the intent
theIntent = intent;
// Get the extra data
getData();
// Do calculations and get new initial battery level for next alarm
int endBatt = calculateHelper(initialBatt);
// Set up alarm manager to wait and then execute next step
AlarmManager AM = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent svcIntent1 = new Intent(Service.getObject(), AlarmReceiver.class);
svcIntent1.putExtra("timeToUse", timeToUse);
svcIntent1.putExtra("interval", interval);
svcIntent1.putExtra("rawTime", rawTime);
svcIntent1.putExtra("initialBatt", endBatt);
svcIntent1.putExtra("sounds", context.notificationSounds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(Service.getObject(), 0, svcIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
// Get times
long timeNow = dateNow.getTime();
int waitTime = interval * 60000;
// Debug stuff
// int waitTime = 15000;
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd hh:mm:ss a");
System.out.println("The current time is " + sdf.format(dateNow));
Toast.makeText(context, "The current time is " + sdf.format(dateNow), Toast.LENGTH_LONG).show();
Date n = new Date();
n.setTime(timeNow+waitTime);
System.out.println("Next calculation will complete at " + sdf.format(n));
Toast.makeText(context, "Next calculation will complete at " + sdf.format(n), Toast.LENGTH_LONG).show();
// Setting the next alarm
AM.setExact(AlarmManager.RTC_WAKEUP, timeNow + waitTime, pendingIntent);
}
else
notify0(10,"ERROR", "ERROR", "Intent is null", true);
}
そして私のマニフェストでは...
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
私の新しいコード (Larry Schiefer の提案に感謝)
また、WakefulBroadcastReceiver によって WakeLock が保持されていても、OS がサービスを閉じると、WakeLock なしで再起動されることもわかりました。そのため、onStartCommand 内で処理するために追加のウェイクロックを取得する必要がある場合があります。私の場合は必須です。
私の奉仕では
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Acquire WakeLock
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Service WakeLock");
wl.acquire();
// Set up global intent reference
theIntent = intent;
if (theIntent != null) {
getData();
if (intent.getAction().equals("Start_Interval")) {
doStart();
}
else if(intent.getAction().equals("End_Interval")){
doEnd();
}
}
else{
Log.e("ERROR", "The intent is NULL inside of onStartCommand. Activity closed?");
cancelAlarm();
stopSelf();
}
// Release WakeLock
wl.release();
return START_STICKY;
}
そして、私の onReceive - 「extends BroadcastReceiver」を「extends WakefulBroadcastReceiver」に変更しました
@Override
public void onReceive(Context c, Intent intent) {
if(intent != null){
// Debug
Log.d("Debug","Alarm broadcast received.");
// Set up the global intent reference
theIntent = intent;
// Set up service context reference
context = Service.getObject();
// Get data from the intent
getData();
// Set up the new intent
Log.d("Debug", "Setting up new intent with context: " + c + " and class: " + Service.class);
Intent service = new Intent(c, Service.class);
service.putExtra("timeToUse", timeToUse);
service.putExtra("interval", interval);
service.putExtra("rawTime", rawTime);
service.putExtra("initialBatt", initialBatt);
service.setAction("End_Interval");
// Wake up the service and complete this interval's calculations
startWakefulService(c, service);
}
else {
context.cancelAlarm();
context.stopSelf();
}
}