kotlin - Android Studio - Kotlin如何將對服務的引用設為null?

137 2

我正在嘗試將Google的LocationsUpdatesForegroundService例子改編為Kotlin以在我的應用程序中使用,現在,一切正常,直到我需要引用一個等於null的服務,

我的Main Activity的相關代碼:


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)



时间: 原作者:

124 0

你將lservice聲明為:


private var lservice: LocService



這意味著它不可為空; Kotlin不允許你將其設置為null 。

(特別要注意,null將始終引發異常:運算符告訴編譯器將表達式處理為非null,由於null顯然是空的,所以你將得到一個錯誤拋出,

如果要允許服務為空,則必須將它聲明為:


private var lservice: LocService?



類型中的?表示它是可空的,但是,在使用它時,你需要檢查它是否為空,以防止NullPointerException出現。

原作者:
...