Android Studio-Kotlin-如何使对服务的引用为空?
我正在尝试将Google的LocationSupdatesForgroundService示例改编为Kotlin,以便在我的应用程序中使用。现在,一切都很顺利,直到我需要引用一个等于null的服务。这不会在其源代码的Java代码中产生任何问题,但是,当我尝试在Kotlin中实现它时,即使使用null!!,当我尝试运行应用程序时,我收到KotlinNullPointerException,应用程序崩溃。我不太确定如何避免这种情况或以不同的方式设置它。我花了几个小时在这上面,有时浏览StackOverFlow,却没有真正找到解决方案。如果有人能帮助我,我将不胜感激。我已经附上了我要离开这里的代码的链接: …以及我在下面使用的必要代码 我的主要活动的相关代码:Android Studio-Kotlin-如何使对服务的引用为空?,kotlin,service,nullpointerexception,Kotlin,Service,Nullpointerexception,我正在尝试将Google的LocationSupdatesForgroundService示例改编为Kotlin,以便在我的应用程序中使用。现在,一切都很顺利,直到我需要引用一个等于null的服务。这不会在其源代码的Java代码中产生任何问题,但是,当我尝试在Kotlin中实现它时,即使使用null!!,当我尝试运行应用程序时,我收到KotlinNullPointerException,应用程序崩溃。我不太确定如何避免这种情况或以不同的方式设置它。我花了几个小时在这上面,有时浏览StackOve
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
}
}
My service类,它可能是或可能不是帮助调试此错误所必需的:
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()
}
}
}
class-LocService:Service(){
private val PACKAGE_NAME=“com.example.localization”
private val TAG=LocService::class.java!!.getSimpleName()
val ACTION_BROADCAST=包名称+“.BROADCAST”
private val EXTRA_从_通知启动=包名称+“。从_通知启动”
//返回服务的当前实例
private val binder=LocalBinder()
//检查有界活动是否已实际消失
//而不是作为方向更改的一部分解除绑定
私有变量changingConfig=false
私有lateinit var fusedLocationClient:FusedLocationProviderClient//For fusedLocationProviderAPI
私有lateinit var locRequest:LocationRequest//FusedLocationProvider的参数
//位置更改的回调
私有lateinit var locCallback:LocationCallback
私有lateinit var serviceHandler:处理程序
私有lateinit var notificationManager:notificationManager//notificationManager
私有lateinit var loc:位置//当前位置
//为前台服务显示的通知的标识符
私人val通知_ID=12345678
//在创建服务时设置
重写fun onCreate()
{
//融合位置提供程序客户端的实例
FusedLocationClient=LocationServices.getFusedLocationProviderClient(此)
//获取位置回调
locCallback=object:LocationCallback(){
覆盖趣味onLocationResult(locationResult:locationResult?){
super.onLocationResult(位置结果)
loc=locationResult!!.getLastLocation()//获取最后一个位置
//向任何广播接收器发送位置信息
val意向=意向(行动和广播)
intention.putExtra(“坐标”,locationResult!!.getLastLocation())
意向。putExtra(“地址”,getAddress(locationResult))
intention.putExtra(“时间”,SimpleDateFormat(“MM/dd/yyyy”at'HH:MM”)。格式(Date())
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(意图)
//如果服务在前台运行,请更改通知内容
如果(服务正在运行前台)(this@LocService))
{
notificationManager.notify(NOTIFICATION\u ID,getNotification())
}
}
}
//创建位置请求并获取最后一个位置
getLastLocation()
buildLocReq()
//创建HandlerThread,它是Thread和works的扩展
//带有活套,意味着它可以在后台处理多个作业
//线程。循环器是保持线程活动的工具。通知管理器
//是否有通知服务通知用户
val handlerThread=handlerThread(标记)
handlerThread.start()
serviceHandler=Handler(handlerThread.getLooper())
notificationManager=getSystemService(通知服务)作为notificationManager
}
//每当客户端使用startService()启动服务时调用
覆盖启动命令(intent:intent?,标志:Int,startId:Int):Int{
val startedFromNotification=intent!!.getBooleanExtra(从通知开始的额外内容,false)
return START\u NOT\u STICKY//停止服务后不要重新创建服务
}
覆盖配置更改(newConfig:Configuration){
super.onConfigurationChanged(newConfig)
changingConfig=true
}
//当客户端到达前台并绑定时调用
//使用此服务。该服务将不再是前台
//发生这种情况时提供服务
覆盖有趣的onBind(意图:意图):IBinder{
停止前景(真)
changingConfig=false
回程活页夹
}
//当客户端返回前台时调用
//并再次绑定此服务。该服务将
//当这种情况发生时,停止成为前台服务
覆盖重新绑定的乐趣(意图:意图?){
停止前景(真)
changingConfig=false
super.onRebind(意图)
}
//当客户端与服务解除绑定时调用。如果调用
//在配置更改时,不执行任何操作。否则,请创建服务
//前台服务
重写onUnbind(意图:意图?):布尔值{
如果(!changingConfig&&RequestingLocationUpdate(此))
{
startForeground(通知\u ID,getNotification())
}
返回真值
}
//当服务被破坏时调用
重写onDestroy(){
serviceHandler.removeCallbacksAndMessages(空)
}
内部类LocalBinder:Binder()
{
fun getService():LocService
{
返回this@LocService
}
}
//用于获取位置请求
私人娱乐buildLocReq()
{
//创建位置请求以存储请求的参数
locRequest=LocationRequest.create()
//设置请求的优先级、间隔和最小位移
locRequest.priority=LocationRequest.priority\u高精度
locRequest.interval=5000
//locRequest.smallestDisplacement=10f
}
私人娱乐getLastLocation(){
尝试
{
fusedLocClient.getLas
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)
private var lservice: LocService
private var lservice: LocService?