Android服务-后台联网

时间:2018-08-08 07:05:57

标签: android networking kotlin

我正在尝试构建一个使用后台位置跟踪的应用程序。我需要每20分钟获取一次设备位置,并将其发送到后端服务器。我做了一个简单的服务:

class GeolocationService : Service() {
    companion object {
        val TAG: String = GeolocationService::class.java.simpleName
        val INTERVAL: Long = 1000 * 60 * 5
        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) {
                    Log.d(TAG, service.service.className)
                    Log.d(TAG, GeolocationService::class.java.name)
                    return true
                }
            }
            return false
        }
    }

    @Inject
    lateinit var geolocationRepository: GeolocationRepository
    private lateinit var providerClient: FusedLocationProviderClient
    private lateinit var locationRequest: LocationRequest
    private lateinit var mGoogleApiClient: GoogleApiClient
    private var locationCallback: LocationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult?) {
            if (locationResult == null) {
                Log.d(TAG, "locationCallback - locationResult is null!")
                providerClient.removeLocationUpdates(this)
                return
            }

            for (location in locationResult.locations) {
                val latitude = location?.latitude ?: 0.0
                val longitude = location?.longitude ?: 0.0

                Log.d(TAG, "Location: $latitude, $longitude")
                Log.d(TAG, "Token: ${UserDataManager.SaveSharedPreference.getApplicationToken(baseContext)?:""}")
                providerClient.removeLocationUpdates(this)
                //showNotification(latitude, longitude, UserDataManager.SaveSharedPreference.getApplicationToken(baseContext)?:"")
                updateCustomerPositionOnServer(latitude, longitude, UserDataManager.SaveSharedPreference.getApplicationToken(baseContext)?:"")
            }
        }
    }

    override fun onBind(intent: Intent?): IBinder {
        return null!!
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        Log.d(TAG, "onStartCommand")
        requestLocation()
        return START_STICKY
    }

    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "onCreate")

        mGoogleApiClient = GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addOnConnectionFailedListener {
                    Log.d(TAG, "onConnectionFailed")
                }
                .addConnectionCallbacks(object : GoogleApiClient.ConnectionCallbacks {
                    override fun onConnectionSuspended(p0: Int) {
                        Log.d(TAG, "onConnectionSuspended")
                    }

                    override fun onConnected(p0: Bundle?) {
                        Log.d(TAG, "onConnected")
                    }

                })
                .build()

        mGoogleApiClient.connect()
        (application as UpMenuApplication).appComponent.inject(this)
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy")
    }

    private fun requestLocation() {
        providerClient = LocationServices.getFusedLocationProviderClient(UpMenuApplication.appContext)
        locationRequest = createLocationRequest()

        try {
            val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
            if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
                providerClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
            } else {
                providerClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
            }
        } catch (e: SecurityException) {
            e.printStackTrace()
        }
    }

    private fun updateCustomerPositionOnServer(lat: Double, lng: Double, token: String) {
        val location = object {
            var latitude: Double = lat
            var longitude: Double = lng
        }

        geolocationRepository.updateCustomerPosition(token, location).enqueue(object: Callback<Void> {
            override fun onFailure(call: Call<Void>?, t: Throwable?) {
                Log.d(TAG, "updateCustomerPosition failed")
            }

            override fun onResponse(call: Call<Void>?, response: Response<Void>?) {
                Log.d(TAG, "updateCustomerPosition success")
            }

        })
    }

    private fun showNotification(lat: Double, lng: Double, token: String) {
        val intent = Intent(baseContext, GeolocationService::class.java)
        val pIntent = PendingIntent.getActivity(baseContext, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT)

        val n = NotificationCompat.Builder(baseContext, "GeolocationService channel")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(GeolocationService::class.java.simpleName)
                .setContentText("${LocalDateTime.now()} - lat: $lat, lng: $lng")
                .setStyle(NotificationCompat.BigTextStyle().bigText("${LocalDateTime.now()} - lat: $lat, lng: $lng. Token: $token"))
                .setContentIntent(pIntent)
                .setVibrate(longArrayOf(1000, 1000, 1000))
                .setLights(Color.RED, 3000, 3000)
                .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
                .setAutoCancel(true)

        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        notificationManager.notify(notificationId++, n.build())
    }

    private fun createLocationRequest(): LocationRequest {
        val locationRequest = LocationRequest()
        locationRequest.interval = 1500
        locationRequest.fastestInterval = 1500
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        return locationRequest
    }
}

我这样开始这项服务:

private fun checkAndStartGeolocation() {
    if (!GeolocationService.isServiceRunning()) {
        Log.d("GeolocationService", "Started all services")
        val intent = Intent(this, GeolocationService::class.java)
        val pendingIntent = PendingIntent.getService(this, 0, intent, 0)
        val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), GeolocationService.INTERVAL, pendingIntent)
    }
}

服务每20分钟运行一次(虽然不完全准确,但准确度已足够),并且设备位置已正确获取且网络正常运行。当手机被锁定时,问题就开始了,因为在每个HTTP请求中,我都会收到此错误:

  

java.net.UnknowHostException:无法解析主机“ api.somehost.com”:没有与主机名关联的地址

在不唤醒设备的情况下是否可以通过后台服务联网?

0 个答案:

没有答案