Android FusedLocationProviderClient始终为null,locationAvailability通常为false

Android FusedLocationProviderClient始终为null,locationAvailability通常为false,android,android-jobscheduler,fusedlocationproviderclient,Android,Android Jobscheduler,Fusedlocationproviderclient,我正在使用jobScheduler获取后台位置更新。但每次安排作业时,FusedLocationProviderClient都为null。为什么呢?我已经检查了(FusedLocationProviderClient==null)条件,并且每次调度作业时,它下面的代码都会运行(这意味着FusedLocationProviderClient在初始化后为null)。请查看下面的代码。此外,locationAvailability通常为false,因此不会调用提供空位置值的onLocationResu

我正在使用jobScheduler获取后台位置更新。但每次安排作业时,FusedLocationProviderClient都为null。为什么呢?我已经检查了(FusedLocationProviderClient==null)条件,并且每次调度作业时,它下面的代码都会运行(这意味着FusedLocationProviderClient在初始化后为null)。请查看下面的代码。此外,locationAvailability通常为false,因此不会调用提供空位置值的onLocationResult。如何优化FusedLocationProviderClient。还有一件事,fusedLocationProviderClient是否始终为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]

< JobScheduler >仅来自21 API,考虑使用<代码> JooTunService < /C> >从<代码>广播接收器< /> >从代码>悬空意图> /代码>,并从<>代码> FuffDealStasePosivCuffel.RealestLoestOptudio< < /Case>方法开始。 它将如下所示:

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
    }
}
class MainActivity:Activity(){
...
lateinit var mFusedLocationClient:FusedLocationProviderClient
lateinit变量mlLocationRequestBackground:LocationRequest
乐趣无限{
mFusedLocationClient=LocationServices.getFusedLocationProviderClient(活动=此)
mlLocationRequestBackground=LocationRequest()
mLocationRequestBackground.interval=UPDATE_interval_IN_millides_BACKGROUND//15分钟-您希望在这个时间间隔内获得更新,在后台,在Android Oreo上每小时不超过几次
mLocationRequestBackground.fastestInterval=最快的更新时间间隔(以毫秒为单位)后台//即1分钟-更新速度不会超过此速度
mlLocationRequestBackground.priority=LocationRequest.priority\u BALANCED\u POWER\u准确性//不要用请求压倒用户的设备,而是使用来自其他应用程序的请求
mlLocationRequestBackground.smallestDisplacement=25f//触发更新的距离(以米为单位)
}
...
乐在其中{
//在后台开始更新
mFusedLocationClient.RequestLocationUpdate(MLLocationRequestBackground,
LocationBroadcastReceiver.GetPendingContent(活动=此))
}
...
}
类LocationBroadcastReceiver:BroadcastReceiver(){
伴星{
const val额外纬度=“额外纬度”
const val EXTRA_longide=“EXTRA_longide”
const val WAKEUP=“com.appid.intent.action.WAKEUP”
fun GetPendingEvent(上下文:context,userId:String?=null):PendingEvent{
val alarmIntent=Intent(上下文,LocationBroadcastReceiver::class.java)
alarmIntent.action=唤醒
返回PendingEvent.getBroadcast(上下文,0,alarmIntent,PendingEvent.FLAG_UPDATE_CURRENT)
}
}
覆盖接收(上下文:上下文?,意图:意图?){
上下文?:返回
如果(意图?.action!=唤醒)返回
val位置:LocationResult?=LocationResult.extractResult(意图)
val loc:位置?=位置?.lastLocation
loc?申请{
val i=Intent(上下文,SendLocationService::class.java)
i、 putExtra(额外纬度、纬度)
i、 putExtra(额外经度,经度)
SendLocationService.enqueueWork(上下文,i)
}
}
}
类SendLocationService:JobIntentService(){
伴星{
私人const val JOB_ID=1000
const val TAG=“SendLocationService”
有趣的排队工作(上下文:上下文,工作:意图){
排队工作(上下文,SendLocationService::class.java,作业ID,工作)
}
}
私有变量发送:布尔值=false
override fun on HandleWork(意图:意图)=运行阻塞{
val latitude=intent.GetDoubleExtrade(LocationBroadcastReceiver.EXTRA_latitude,0.0)
val经度=intent.getDoubleExtra(LocationBroadcastReceiver.EXTRA_经度,0.0)
suspendCoroutine{continuation->
YourApi.postMyLocation(纬度=纬度,lng=经度)
.callback{continuation.resume(单位)}
}
}
重写onStopCurrentWork():布尔值{
返回!发送
}
}
别忘了将它们添加到清单中

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

我也遇到过同样的问题

我犯的第一个错误是没有保证
removeLocationUpdates
将在与
requestLocationUpdates
相同的线程上运行。实际上,它不必是同一个线程,但是在
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())
    }
  }

我希望我犯的三个错误和解决方法对你有帮助

您正在哪个Android版本上测试此功能?@AlessandroVerona您正在链接一个不推荐的(因此不太相关)使用位置服务的方法。@GergelyKőrössy Android 8.0版。0@AlessandroVerona我想我不需要在FusedLocationProviderClientIt中调用GoogleAppClient,这可能是一个限制。请尝试通过强制设备输入Doze.poqw来测试您的代码,您能详细说明上面文章中的以下代码片段吗?>这种解释是不恰当的,但最终,如果调用requestLocationUpdates一次,则必须在下一次requestLocationUpdates之前由interval触发位置更新事件。找到这个bug是最困难的。@N0000B很抱歉我解释得不好。正如我在回答中提到的,
interval
触发Android系统的位置更新事件。如果调用
requestLocationUpdates
时没有位置更新,则在发生新的位置更新之前,将永远不会调用
onLocationResult
回调。
LocationRequest.apply {
  priority = PRIORITY_HIGH_ACCURACY
  interval = 10000L
}