Я пытаюсь адаптировать пример Google LocationsUpdatesForegroundService в Kotlin для использования в моем приложении. Теперь все идет хорошо, пока мне не нужно сделать ссылку на сервис, равный нулю. Это не вызывает никаких проблем в Java-коде, из которого он происходит, но когда я пытаюсь реализовать его в Kotlin, даже если использую null !!, я получаю исключение KotlinNullPointerException, когда пытаюсь запустить приложение и приложение аварийно завершает работу. Я не совсем уверен, как избежать этого или установить это по-другому. Я потратил несколько часов на это и иногда просматривал StackOverFlow, не имея возможности найти решение для него. Если бы кто-нибудь мог мне помочь, это было бы очень признательно. Я приложил ссылку к коду, из которого я ухожу:
https://github.com/android/location-samples/blob/master/LocationUpdatesForegroundService/app/src/main/java/com/google/android/gms/location/sample/locationupdatesforegroundservice/MainActivity.java#L127
... и необходимый код, который я использую ниже.
Соответствующий код из моей основной деятельности:
private var lservice : LocService = null!! // A reference to the service to get location updates
private var bound = false // Tracks the bound state of the service
// Monitors the state of the connection to the service.
private val mServiceConnection = object:ServiceConnection {
override fun onServiceConnected(name:ComponentName, service: IBinder) {
val binder : LocService.LocalBinder = service as LocService.LocalBinder
lservice = binder.getService()
bound = true
}
override fun onServiceDisconnected(name: ComponentName) {
lservice = null!!
bound = false
}
}
Мой класс обслуживания, который может или не может быть необходим для помощи в отладке этой ошибки:
class LocService : Service() {
private val PACKAGE_NAME = "com.example.localization"
private val TAG = LocService::class.java!!.getSimpleName()
val ACTION_BROADCAST = PACKAGE_NAME + ".broadcast"
private val EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME + ".started_from_notification"
// To return a current instance of the service
private val binder = LocalBinder()
// To check if the bounded activity has actually gone away
// and not unbound as part of an orientation change
private var changingConfig = false
private lateinit var fusedLocClient: FusedLocationProviderClient // For FusedLocationProvider API
private lateinit var locRequest : LocationRequest // Parameters for FusedLocationProvider
// Callback for changes in location
private lateinit var locCallback: LocationCallback
private lateinit var serviceHandler : Handler
private lateinit var notificationManager : NotificationManager // Notification Manager
private lateinit var loc : Location // The current location
// The identifier for the notification displayed for the foreground service
private val NOTIFICATION_ID = 12345678
// Set up when the service is created
override fun onCreate()
{
// An instance of Fused Location Provider Client
fusedLocClient = LocationServices.getFusedLocationProviderClient(this)
// Obtains location callback
locCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
super.onLocationResult(locationResult)
loc = locationResult!!.getLastLocation() // Obtains last location
// Send location information to any broadcast receivers
val intention = Intent(ACTION_BROADCAST)
intention.putExtra("Coordinates", locationResult!!.getLastLocation())
intention.putExtra("Address", getAddress(locationResult))
intention.putExtra("Time", SimpleDateFormat("MM/dd/yyyy 'at' HH:mm").format(Date()))
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intention)
// Change notification content if the service is running in the foreground
if (serviceIsRunningInForeground(this@LocService))
{
notificationManager.notify(NOTIFICATION_ID, getNotification())
}
}
}
// Create location request and get the last location
getLastLocation()
buildLocReq()
// Creates a HandlerThread, which is an extension of Thread and works
// with a Looper, meaning it's meant to handle multiple jobs in the background
// thread. The Looper is what keeps the thread alive. Notification Manager
// is there to notify the user of the notification service
val handlerThread = HandlerThread(TAG)
handlerThread.start()
serviceHandler = Handler(handlerThread.getLooper())
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
// Called whenever the client starts the service using startService()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val startedFromNotification = intent!!.getBooleanExtra(EXTRA_STARTED_FROM_NOTIFICATION, false)
return START_NOT_STICKY // Don't recreate the service after it's killed
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
changingConfig = true
}
// Called when the client comes to the foreground and binds
// with this service. The service will stop being a foreground
// service when that happens
override fun onBind(intent: Intent): IBinder {
stopForeground(true)
changingConfig = false
return binder
}
// Called when the client returns to the foreground
// and binds once again with this service. The service will
// stop being a foreground service when that happens
override fun onRebind(intent: Intent?) {
stopForeground(true)
changingConfig = false
super.onRebind(intent)
}
// Called when the client unbinds with the service. If it's called
// with a configuration change, do nothing. Otherwise, make the service
// a foreground service
override fun onUnbind(intent: Intent?): Boolean {
if (!changingConfig && requestingLocationUpdates(this))
{
startForeground(NOTIFICATION_ID, getNotification())
}
return true
}
// Called when service is destroyed
override fun onDestroy() {
serviceHandler.removeCallbacksAndMessages(null)
}
inner class LocalBinder : Binder()
{
fun getService() : LocService
{
return this@LocService
}
}
// For obtaining location request
private fun buildLocReq()
{
// Create a location request to store parameters for the requests
locRequest = LocationRequest.create()
// Sets priority, interval, and --smallest displacement-- for requests
locRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
locRequest.interval = 5000
// locRequest.smallestDisplacement = 10f
}
private fun getLastLocation() {
try
{
fusedLocClient.getLastLocation()
.addOnCompleteListener(object:OnCompleteListener<Location>
{
override fun onComplete(@NonNull task:Task<Location>) {
if (task.isSuccessful() && task.getResult() != null)
{
loc = task.getResult() as Location
}
else
{
Log.w(TAG, "Failed to get location.")
}
}
})
}
catch (unlikely:SecurityException) {
Log.e(TAG, "Lost location permission." + unlikely)
}
}
fun requestLocationUpdates()
{
setRequestingLocationUpdates(this, true)
startService(Intent(getApplicationContext(), LocService::class.java))
try
{
fusedLocClient.requestLocationUpdates(locRequest, locCallback, Looper.myLooper())
} catch (unlikely:SecurityException)
{
setRequestingLocationUpdates(this, false)
Log.e(TAG, "Lost location permission. Couldn't request updates. " + unlikely)
}
}
// Obtain address via GeoCoder class
private fun getAddress(locResult: LocationResult?): String {
var address = ""
var geoCoder = Geocoder(this, Locale.getDefault())
var loc1 = locResult!!.locations.get(locResult.locations.size-1)
try {
var addresses:ArrayList<Address> = geoCoder.getFromLocation(loc1.latitude, loc1.longitude, 1) as ArrayList<Address>
address = addresses.get(0).getAddressLine(0)
} catch (e: IOException) {
e.printStackTrace()
}
return address
}
private fun getNotification(): Notification {
val intent = Intent(this, LocService::class.java)
val text = getLocationText(loc)
val builder = NotificationCompat.Builder(this)
.setContentText(text)
.setOngoing(true)
.setPriority(Notification.PRIORITY_HIGH)
.setTicker(text)
.setWhen(System.currentTimeMillis())
return builder.build()
}
// Checks to see if the service is running in the foreground or not
fun serviceIsRunningInForeground(context: Context) : Boolean
{
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
for (service in manager.getRunningServices(Integer.MAX_VALUE))
{
if (javaClass.getName().equals(service.service.getClassName()))
{
if (service.foreground)
{
return true
}
}
}
return false
}
val KEY_REQUESTING_LOCATION_UPDATES = "requesting_locaction_updates"
// Returns true if the requesting location updates, else false
fun requestingLocationUpdates(context: Context): Boolean {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false)
}
// Stores the location updates state in SharedPreferences
fun setRequestingLocationUpdates(context: Context, requestingLocationUpdates: Boolean)
{
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(KEY_REQUESTING_LOCATION_UPDATES, requestingLocationUpdates).apply()
}
// Returns the coordinates as a string for the notifications
fun getLocationText(loc: Location) : String
{
if (loc == null) {
return "Unknown Location"
} else {
return "Latitude: " + loc.longitude.toString() + " | Longitude: " + loc.longitude.toString()
}
}
}
Вот ошибка:
11-01 00:27:36.923 15995-15995/com.example.localization E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.localization, PID: 15995
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.localization/com.example.localization.MainActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2327)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: kotlin.KotlinNullPointerException
at com.example.localization.MainActivity.<init>(MainActivity.kt:40)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1067)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2317)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)