Android-具有网络通话功能的后台服务

时间:2018-08-10 07:19:34

标签: android firebase android-service doze

我需要创建每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)
}

0 个答案:

没有答案