I'm been having this problem, I couldn't find related question, although the errors were similar they seemed to be different problem.
Before I state the problem, I tested this on my android emulator and all the code works fine! But when I run tested on two android devices with older and same android version, there is the following problem:
java.lang.RuntimeException: Unable to start service me.xxx.landmarkapp.XXXService@3ab946ed with Intent { cmp=me.xxx.landmarkapp/.XXXService}: kotlin.KotlinNullPointerException
The service won't start (it worked fine on android emulator, service code worked perfectly).
Here is how I start the service.
val serviceIntent = Intent(applicationContext, XXXService::class.java)
startService(serviceIntent)
I assume the service code is irrelevant.
I have checked to make sure applicationContext
variable is not null (by Log.d
it on screen), as I thought this might be the null pointer issue.
I also have made sure to call super.onCreate(savedInstanceState);
at the top of overrided onCreate
method in this activity, this seemed to be the issue in other questions.
Another issue in other questions which I seem to be doing right, is I defined the service in Manifest.xml
...
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.xxx.landmarkapp" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
... >
<activity android:name=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".XXXService" >
</service>
</application>
</manifest>
Does anyone know what the issue is? I've been stuck at this for hours
(BTW I'm using Kotlin, but I'm sure it's the same problem Java)
EDIT:
Service code
package me.xxx.landmarkapp
class XXXService: Service(), LocationListener {
////////////////////////////////////////
// NOTIFICATIONS
////////////////////////////////////////
private lateinit var notificationManager: NotificationManager
private val CHANNEL_ID = "my_channel_01"
private val NOTIFICATION_ID_SERVICE = 1
private val NOTIFICATION_ID_LANDMARK = 2
private fun initNotifications() {
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, CHANNEL_ID, importance).apply {
description = CHANNEL_ID
}
notificationManager.createNotificationChannel(channel)
}
}
private fun buildNotification(title: String, message: String, intent: PendingIntent?): Notification {
return NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.messageicon)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(intent)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
}
private fun produceNotification(id: Int, title: String, message: String) {
val notification = buildNotification(title, message, null)
with(NotificationManagerCompat.from(this)) {
notify(id, notification)
}
}
////////////////////////////////////////
// LOCATION
////////////////////////////////////////
private var lat: Double = 0.toDouble()
private var long: Double = 0.toDouble()
private fun enableLocation() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
val criteria = Criteria()
val provider = locationManager.getBestProvider(criteria, false)
val location = locationManager.getLastKnownLocation(provider)
locationManager.requestLocationUpdates(provider, 5000, 20f, this)
setLocation(location)
} else {
produceNotification(NOTIFICATION_ID_LANDMARK, "Landmark App", "Location permission error")
}
}
private fun disableLocation() {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(this)
}
private fun setLocation(location: Location?) {
lat = location!!.latitude
long = location.longitude
findLandmarks()
}
override fun onLocationChanged(location: Location?) {
setLocation(location)
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
}
////////////////////////////////////////
// LANDMARKS
////////////////////////////////////////
private val client = OkHttpClient()
private fun findLandmarks() {
val request = Request.Builder()
.url("https://example.com/?userLat=$lat&userLong=$long")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
produceNotification(NOTIFICATION_ID_LANDMARK, "Landmark App", "Network error")
}
override fun onResponse(call: Call, response: Response) {
val msg = response.body()?.string()
if (msg != null)
{
val landmarks = JSONObject(msg).getJSONArray("landmarks")
for (i in 0 until landmarks.length()) {
val landmark = landmarks.getJSONObject(i)
// val id = landmark.getString("id")
val name = landmark.getString("name")
val location = landmark.getJSONObject("location")
val latitude = location.getString("latitude").toFloatOrNull()
val longitude = location.getString("longitude").toFloatOrNull()
// TODO: unique id for each notification
produceNotification(NOTIFICATION_ID_LANDMARK, "Found Landmark: $name!", "Latitude: $latitude, Longitude: $longitude")
}
}
}
})
}
////////////////////////////////////////
// SERVICE
////////////////////////////////////////
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
initNotifications()
val intent: PendingIntent =
Intent(this, MainActivity::class.java).let { notificationIntent ->
PendingIntent.getActivity(this, 0, notificationIntent, 0)
}
val notification = buildNotification("Landmark App", "Service running", intent)
startForeground(NOTIFICATION_ID_SERVICE, notification)
}
override fun onDestroy() {
super.onDestroy()
disableLocation()
}
override fun onStartCommand(intent: Intent, flags: Int, startid: Int): Int {
enableLocation()
return START_STICKY
}
}
Stack trace:
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3086)
at android.app.ActivityThread.access$2200(ActivityThread.java:163)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1465)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5608)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1397)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1192)
Caused by: kotlin.KotlinNullPointerException
at me.xxx.landmarkapp.XXXService.setLocation(XXXService.kt:92)
at me.xxx.landmarkapp.XXXService.enableLocation(XXXService.kt:80)
at me.xxx.landmarkapp.XXService.onStartCommand(XXXService.kt:181)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3069)
at android.app.ActivityThread.access$2200(ActivityThread.java:163)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1465)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5608)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)