Я реализовал точно такой же пример службы LocationUpdateForeground, как и в этих местоположениях-образцах . Проблема в том, что когда я запускаю предоставленный проект, он запускается, но, поскольку я работаю с Kotlin, а эти проекты находятся в Java, мое приложение падает и выдает исключение нулевого указателя на mService!!.removeLocationUpdates()
, но я попытался скопировать его то же самое без каких-либо изменений, и он все еще падает.
Я застрял на получении фонового местоположения, так как большинство из них не работают, и этот работает точно даже в Android Q.
Ошибка возникает из-за того, что onServiceConnected()
никогда не вызывается при инициализации mService
.
Манифест. xml
<service
android:name="com.app.writer.LocationUpdatesService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
MainActivity
class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {
var prevMenuItem: MenuItem? = null
private lateinit var tinyDB: TinyDB
private lateinit var myApi: INodeJS
private lateinit var mySnackbar: Snackbar
private var compositeDisposable = CompositeDisposable()
private var mServiceBinder: LocationUpdatesService.LocalBinder? = null
private val TAG = MainActivity::class.java.simpleName
// Used in checking for runtime permissions.
private val REQUEST_PERMISSIONS_REQUEST_CODE = 34
// The BroadcastReceiver used to listen from broadcasts from the service.
private var myReceiver: MainActivity.MyReceiver? =
null
// A reference to the service used to get location updates.
private var mService: LocationUpdatesService? = null
// Tracks the bound state of the service.
private var mBound = false
private val mServiceConnection: ServiceConnection = object :
ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
mServiceBinder = service as LocationUpdatesService.LocalBinder
mService = mServiceBinder!!.service
mBound = true
}
override fun onServiceDisconnected(name: ComponentName) {
mService = null
mBound = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
tinyDB = TinyDB(this) //Easy way to save data in SharedPreferences
myReceiver = MyReceiver()
// Check that the user hasn't revoked permissions by going to Settings.
if (Utils.requestingLocationUpdates(this)) {
if (!checkPermissions()) {
requestPermissions()
}
}
}
override fun onDestroy() {
super.onDestroy()
}
override fun onStop() {
if (mBound) {
// Unbind from the service. This signals to the service that this activity is no longer
// in the foreground, and the service can respond by promoting itself to a foreground
// service.
unbindService(mServiceConnection)
mBound = false
}
PreferenceManager.getDefaultSharedPreferences(this)
.unregisterOnSharedPreferenceChangeListener(this)
super.onStop()
}
override fun onStart() {
super.onStart()
PreferenceManager.getDefaultSharedPreferences(this)
.registerOnSharedPreferenceChangeListener(this)
Writer.setOnClickListener{
if (!checkPermissions()) {
requestPermissions()
} else {
if (tinyDB.getBoolean("Writer")) {
mySnackbar.setText("Kavach Disabled!!!").show()
} else {
mService!!.requestLocationUpdates()
}
}
}
// Restore the state of the buttons when the activity (re)launches.
setButtonsState(Utils.requestingLocationUpdates(this))
// Bind to the service. If the service is in foreground mode, this signals to the service
// that since this activity is in the foreground, the service can exit foreground mode.
applicationContext.bindService(
Intent(this, LocationUpdatesService::class.java), mServiceConnection,
Context.BIND_AUTO_CREATE
)
}
override fun onResume() {
super.onResume()
LocalBroadcastManager.getInstance(this).registerReceiver(
myReceiver!!,
IntentFilter(LocationUpdatesService.ACTION_BROADCAST)
)
}
override fun onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver!!)
super.onPause()
}
/**
* Returns the current state of the permissions needed.
*/
private fun checkPermissions(): Boolean {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
}
private fun requestPermissions() {
val shouldProvideRationale =
ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
// Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
if (shouldProvideRationale) {
Log.i(
TAG,
"Displaying permission rationale to provide additional context."
)
mySnackbar.setText("Location permission is needed for core functionality")
.setAction("Ok", View.OnClickListener { // Request permission
ActivityCompat.requestPermissions(
this@MainActivity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSIONS_REQUEST_CODE
)
})
.show()
} else {
Log.i(TAG, "Requesting permission")
// Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
ActivityCompat.requestPermissions(
this@MainActivity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
REQUEST_PERMISSIONS_REQUEST_CODE
)
}
}
/**
* Callback received when a permissions request has been completed.
*/
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String?>,
grantResults: IntArray
) {
Log.i(TAG, "onRequestPermissionResult")
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults.isEmpty()) {
// If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
Log.i(TAG, "User interaction was cancelled.")
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission was granted.
mService!!.requestLocationUpdates()
} else {
// Permission denied.
setButtonsState(false)
mySnackbar.setText("Permission Denied, can't work without it")
.setAction(
R.string.settings
) { // Build intent that displays the App settings screen.
val intent = Intent()
intent.action =
android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID, null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
.show()
}
}
}
/**
* Receiver for broadcasts sent by [LocationUpdatesService].
*/
private class MyReceiver : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
val location =
intent.getParcelableExtra<Location>(LocationUpdatesService.EXTRA_LOCATION)
if (location != null) {
Toast.makeText(
context, Utils.getLocationText(location),
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onSharedPreferenceChanged(
sharedPreferences: SharedPreferences,
s: String
) {
// Update the buttons state depending on whether location updates are being requested.
if (s == Utils.KEY_REQUESTING_LOCATION_UPDATES) {
setButtonsState(
sharedPreferences.getBoolean(
Utils.KEY_REQUESTING_LOCATION_UPDATES,
false
)
)
}
}
private fun setButtonsState(requestingLocationUpdates: Boolean) {
if (!requestingLocationUpdates) {
mService!!.removeLocationUpdates()
} else {
mService!!.requestLocationUpdates()
}
}
}
Я знаю, что такое исключение nullpointer, но здесь я застрял, а также, это происходит из-за onStart.