我需要创建每10-20分钟运行一次的后台服务,并执行一些api网络调用。我试过的是: 1.通过AlarmManager和Receiver通过BOOT_COMPLETED操作进行常规服务。 2. Firebase JobService
在第一种情况下,服务每10到20分钟运行一次,并且在我锁定设备之前,它都可以正常工作。如果设备已定位,服务正在运行,但出现异常:
java.net.UnknowHostException:无法解析主机“ api.somehost.com”:没有与主机名关联的地址
我认为该设备位于Doze中,我的应用程序无法访问网络。
在第二种情况下,当我锁定设备时,作业无法启动。
此服务也正在获取设备位置,但是在两种情况下都可以正常工作,因此为简单起见,我省略了此代码。
AndroidManifest:
<service
android:name=".service.GeolocationService"
android:process=":geolocationServiceUM"
android:enabled="true"
android:exported="false"/>
<receiver
android:name=".receiver.GeolocationBootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.REBOOT"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
<service
android:exported="false"
android:name=".service.GeolocationJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":geolocationJobService">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>
接收器:
class GeolocationBootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d(GeolocationBootReceiver::class.java.simpleName, "GeolocationBootReceiver::onReceiver()")
val ctx = context ?: UpMenuApplication.appContext
GeolocationService.startService(ctx)
}
}
服务:
class GeolocationService : Service() {
companion object {
val TAG: String = GeolocationService::class.java.simpleName
val INTERVAL: Long = 1000 * 60 * 15
var notificationId: Int = 100
fun isServiceRunning(): Boolean {
val activityManager = UpMenuApplication.appContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in activityManager.getRunningServices(Int.MAX_VALUE)) {
if (GeolocationService::class.java.name == service.service.className) {
return true
}
}
return false
}
fun startService(context: Context) {
if (!GeolocationService.isServiceRunning()) {
val intent = Intent(context, GeolocationService::class.java)
val pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (Build.VERSION.SDK_INT >= 23) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, INTERVAL, pendingIntent)
}
else if (Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, INTERVAL, pendingIntent)
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, INTERVAL, pendingIntent)
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), GeolocationService.INTERVAL, pendingIntent)
}
}
}
@Inject
lateinit var geolocationRepository: GeolocationRepository
private var screenWakeLock: PowerManager.WakeLock? = null
override fun onBind(intent: Intent?): IBinder {
return null!!
}
@SuppressLint("InvalidWakeLockTag")
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
try {
val pm = baseContext.getSystemService(Context.POWER_SERVICE) as PowerManager
screenWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ScreenLock tag from AlarmListener");
screenWakeLock?.acquire(30000)
} catch (e: Exception) {
Log.d(TAG, e.message)
}
updateCustomerPositionOnServer(15,49,"token")
return START_STICKY
}
override fun onCreate() {
super.onCreate()
Log.d(TAG, "onCreate")
}
private fun updateCustomerPositionOnServer(lat: Double, lng: Double, token: String) {
val location = Location(lat, lng)
geolocationRepository.updateCustomerPosition(token, location).enqueue(object: Callback<Void> {
override fun onFailure(call: Call<Void>?, t: Throwable?) {
Log.d(TAG, call.toString())
Log.d(TAG, call?.request()?.url()?.toString())
Log.d(TAG, t?.message)
Log.d(TAG, call?.request()?.body()?.toString())
Log.d(TAG, "updateCustomerPosition failed." + t?.toString())
screenWakeLock?.release()
}
override fun onResponse(call: Call<Void>?, response: Response<Void>?) {
Log.d(TAG, "updateCustomerPosition success")
Log.d(TAG,"isSuccess: ${response?.isSuccessful}")
screenWakeLock?.release()
}
})
}
}
起始代码:
private fun checkAndStartGeolocation() {
val jobDispatcher = FirebaseJobDispatcher(GooglePlayDriver(UpMenuApplication.appContext))
val geolocationJob = jobDispatcher.newJobBuilder()
.setService(GeolocationJobService::class.java)
.setTag(GeolocationJobService.TAG)
.setRecurring(true)
.setLifetime(Lifetime.FOREVER)
.setTrigger(Trigger.executionWindow(120, 125))
.setReplaceCurrent(true)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build()
jobDispatcher.mustSchedule(geolocationJob)
GeolocationService.startService(this)
}