FusedLocationProviderClient始终为null,locationAvailability通常为false

时间:2018-03-15 12:13:03

标签: android android-jobscheduler fusedlocationproviderclient

我正在使用jobScheduler获取后台位置更新。但每次调度作业时,FusedLocationProviderClient都为null。这是为什么?我检查了(FusedLocationProviderClient == null)条件,并且每次调度作业时,其下的代码都会运行(这意味着fusedLocationProviderClient在初始化后为null。)请查看下面的代码。此外,locationAvailability通常为false,因此不会调用onLocationResult来提供null位置值。如何优化FusedLocationProviderClient。还有一件事,fuseLocationProviderClient是否始终为null,而locationAvailability是否为false相关?

@Override
public boolean onStartJob(JobParameters jobParameters) {
    Log.e("onStartJob", "onStartJob");//for debug
    jobP = jobParameters;

    if (!checkAndRequestPermissions()) {
        Toast.makeText(this, "Please provide location permission for paramount app.", Toast.LENGTH_LONG).show();
        provider = null;
    } else {
        if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        }
        if (mLocationRequest == null) {
            Log.e("onStartJob", "LocationRequest initialized"); //for debug
            mLocationRequest = LocationRequest.create();
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
            mLocationRequest.setInterval(100 * 1000);
            mLocationRequest.setFastestInterval(60 * 1000);
        }

        if (client == null) {
            Log.e("onStartJob", "client initialized"); //for debug
            client = LocationServices.getFusedLocationProviderClient(this);
            client.requestLocationUpdates(mLocationRequest, new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    Log.e("onLocationResult ", "onLocationResult");
                    onLocationChanged(locationResult.getLastLocation());
                }
                @Override
                public void onLocationAvailability(LocationAvailability locationAvailability) {
                    Log.e("onLocationAvailability", locationAvailability + "");;
                }
            },
            Looper.myLooper());
        }

        try {
            provider = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE) + "";
            gpsProvider = provider;
        } catch (Settings.SettingNotFoundException e) {
            Log.e("provider", "gps provider error");
        }
    }
    return true;
}

@Override
public boolean onStopJob(JobParameters jobParameters) {
    Log.e("onStopJob", "onStopJob");//for debug
    if (ul != null) {
        ul.cancel(true);
    }
    return true;
}

public void onLocationChanged(Location location) {
    latitude = location.getLatitude() + "";
    longitude = location.getLongitude() + "";
    Log.e("latitude" , latitude);
}

上面代码中的日志值如下所示:

03-15 17:09:25.889 10687-10687/com.myProject.com.jobschedulers E/onStartJob: onStartJob
03-15 17:09:25.900 10687-10687/com.myProject.com.jobschedulers E/onstartJob: client initialized
03-15 17:09:25.957 10687-10687/com.myProject.com.jobschedulers E/onLocationResult: onLocationResult
03-15 17:09:25.960 10687-10687/com.myProject.com.jobschedulers E/onLocationAvailability: LocationAvailability[isLocationAvailable: true]
03-15 17:23:26.975 10687-10687/com.myProject.com.jobschedulers E/onStartJob: onStartJob
03-15 17:23:26.993 10687-10687/com.myProject.com.jobschedulers E/onstartJob: client initialized
03-15 17:23:27.017 10687-10687/com.myProject.com.jobschedulers E/onLocationAvailability: LocationAvailability[isLocationAvailable: false]
03-15 17:41:32.672 10687-10687/com.myProject.com.jobschedulers E/onStartJob: onStartJob
03-15 17:41:32.690 10687-10687/com.myProject.com.jobschedulers E/onstartJob: client initialized
03-15 17:41:32.741 10687-10687/com.myProject.com.jobschedulers E/onLocationAvailability: LocationAvailability[isLocationAvailable: false]
03-15 17:53:17.335 10687-10687/com.myProject.com.jobschedulers E/onStartJob: onStartJob
03-15 17:53:17.351 10687-10687/com.myProject.com.jobschedulers E/onstartJob: client initialized
03-15 17:53:17.383 10687-10687/com.myProject.com.jobschedulers E/onLocationAvailability: LocationAvailability[isLocationAvailable: false]

2 个答案:

答案 0 :(得分:0)

JobScheduler仅来自21种API,请考虑使用从JobIntentServiceBroadcastReceiverPendingIntent启动的FusedLocationProviderClient.requestLocationUpdates,并从class MainActivity : Activity() { ... lateinit var mFusedLocationClient:FusedLocationProviderClient lateinit var mLocationRequestBackground: LocationRequest fun init { mFusedLocationClient = LocationServices.getFusedLocationProviderClient(activity = this) mLocationRequestBackground = LocationRequest() mLocationRequestBackground.interval = UPDATE_INTERVAL_IN_MILLISECONDS_BACKGROUND // i.e. 15 minutes - you hope to get updates at this interval, in background it will be not more than few times per hour on Android Oreo mLocationRequestBackground.fastestInterval = FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS_BACKGROUND //i.e. 1 minute - updates will not come faster than this mLocationRequestBackground.priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY //do not overwhelm user's device with requests, but use requests from other apps mLocationRequestBackground.smallestDisplacement = 25f //distance in meters to trigger update } ... fun onStop() { //start updating in background mFusedLocationClient.requestLocationUpdates(mLocationRequestBackground, LocationBroadcastReceiver.getPendingIntent(activity = this)) } ... } class LocationBroadcastReceiver : BroadcastReceiver() { companion object { const val EXTRA_LATITUDE = "EXTRA_LATITUDE" const val EXTRA_LONGITUDE = "EXTRA_LONGITUDE" const val WAKEUP = "com.appid.intent.action.WAKEUP" fun getPendingIntent(context: Context, userId: String? = null): PendingIntent { val alarmIntent = Intent(context, LocationBroadcastReceiver::class.java) alarmIntent.action = WAKEUP return PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT) } } override fun onReceive(context: Context?, intent: Intent?) { context ?: return if (intent?.action != WAKEUP) return val location: LocationResult? = LocationResult.extractResult(intent) val loc: Location? = location?.lastLocation loc?.apply { val i = Intent(context, SendLocationService::class.java) i.putExtra(EXTRA_LATITUDE, latitude) i.putExtra(EXTRA_LONGITUDE, longitude) SendLocationService.enqueueWork(context, i) } } } class SendLocationService : JobIntentService() { companion object { private const val JOB_ID = 1000 const val TAG = "SendLocationService" fun enqueueWork(context: Context, work: Intent) { enqueueWork(context, SendLocationService::class.java, JOB_ID, work) } } private var sending: Boolean = false override fun onHandleWork(intent: Intent) = runBlocking { val latitude = intent.getDoubleExtra(LocationBroadcastReceiver.EXTRA_LATITUDE, 0.0) val longitude = intent.getDoubleExtra(LocationBroadcastReceiver.EXTRA_LONGITUDE, 0.0) suspendCoroutine<Unit> { continuation -> YourApi.postMyLocation(lat = latitude, lng = longitude) .callback { continuation.resume(Unit) } } } override fun onStopCurrentWork(): Boolean { return !sending } } 方法开始。 看起来像这样:

    <service android:name=".services.SendLocationService"
        android:exported="false"
        android:permission="android.permission.BIND_JOB_SERVICE"/>
    <receiver android:name=".services.LocationBroadcastReceiver"
        android:exported="false"/>

别忘了将它们添加到清单

import java.time.Instant;
...
    Instant instant = Instant.parse("2018-01-02T18:14:59.000+01:00")

答案 1 :(得分:0)

我遇到了同样的问题。

我犯的第一个错误是不保证removeLocationUpdatesrequestLocationUpdates在同一线程上运行。实际上,它不必是同一线程,但是在requestLocationUpdates之后,必须调用removeLocationUpdates使下一个requestLocationUpdates有效。为确保这一点,在同一线程上工作要容易得多。

例如:

  private fun FusedLocationProviderClient.requestLocation(
      request: LocationRequest
  ): Single<LocationResult> {
    return Single.create<LocationResult> { emitter ->
      requestLocationUpdates(request, object : LocationCallback() {
        override fun onLocationResult(result: LocationResult?) {
          removeLocationUpdates(object : LocationCallback() {})
              .addOnCompleteListener {
                if (emitter.isDisposed) {
                  info("onLocationResult called after disposing.")
                  return@addOnCompleteListener
                }

                if (result != null && result.locations.isNotEmpty()) {
                  onSuccess(result)
                } else {
                  onError(RuntimeException("Invalid location result"))
                }
              }
        }

        private fun onError(error: Exception) {
          if (!emitter.isDisposed) {
            emitter.onError(error)
          }
        }

        private fun onSuccess(item: LocationResult) {
          if (!emitter.isDisposed) {
            emitter.onSuccess(item)
          }
        }

      }, Looper.getMainLooper())
    }
  }

如代码所示,我已经将Single的emitter吸引到addOnCompleteListener中的removeLocationUpdates上,以确保在removeLocationUpdates之后调用requestLocationUpdates。当然,如果没有RxJava,将更易于实现。

我犯的第二个错误是interval中的LocationRequest设置错误。根据文档:

  

此方法以毫秒为单位设置您的应用希望接收位置更新的速率。请注意,位置更新可能会比此速度快一些或慢一些,以优化电池使用量,或者可能根本没有更新(例如,如果设备没有连接)。

interval触发Android系统的位置更新事件。如果在调用requestLocationUpdates时没有位置更新,则在发生新的位置更新之前,将永远不会调用onLocationResult回调。

我犯的第三个错误是在LocationRequest中设置了错误的priority。在API 10及以下版本中,它不是PRIORITY_BALANCED_POWER_ACCURACY,但是可以通过使用PRIORITY_HIGH_ACCURACY来解决。在这种情况下,我仅在仿真器上进行了测试,因此实际设备可能会有不同的结果。我猜PRIORITY_BALANCED_POWER_ACCURACY似乎不能正常工作,因为该模拟器不提供蓝牙硬件。

所以我的LocationRequest如下:

LocationRequest.apply {
  priority = PRIORITY_HIGH_ACCURACY
  interval = 10000L
}

我希望我犯的三个错误和解决方案对您有所帮助!