Sar*_* HH 10 android google-api kotlin android-geofence firebase-realtime-database
我正在尝试在 android studio 中使用 Kotlin 构建地理围栏应用程序,但虚拟机崩溃了,然后下次运行显示此错误
E/AndroidRuntime:致命异常:主进程:com.example.mapgis,PID:3002 java.lang.NullPointerException:指定为非空的参数为空:方法 kotlin.jvm.internal.Intrinsics.checkNotNullParameter,在 com. example.mapgis.MapsActivity.onMapReady$lambda-2(未知来源:7)位于 com.example.mapgis.MapsActivity。$r8$lambda$j524CuJ2hJLTFNPmiaC5VRpPy0I(未知来源:0)位于 com.example.mapgis.MapsActivity$$ExternalSyntheticLambda2。 onSuccess(来源不明:4)在 com.google.android.gms.tasks.zzm.run(com.google.android.gms:play-services-tasks@@18.0.0:1)在 android.os.Handler。处理回调(Handler.java:873)在android.os.Handler.dispatchMessage(Handler.java:99)在android.os.Looper.loop(Looper.java:193)在android.app.ActivityThread.main(ActivityThread.java :6669)在java.lang.reflect.Method.invoke(本机方法)在com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)在com.android.internal.os.ZygoteInit.main (ZygoteInit.java:858)
代码
package com.example.mapgis
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.location.Location
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.app.JobIntentService
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.example.mapgis.GeofenceReceiver
import com.example.mapgis.R
import com.example.mapgis.Reminder
import com.google.android.gms.location.*
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.tasks.CancellationToken
import com.google.firebase.FirebaseApp
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import java.io.Serializable
import kotlin.random.Random
const val GEOFENCE_RADIUS = 200
const val GEOFENCE_ID = "REMINDER_GEOFENCE_ID"
const val GEOFENCE_EXPIRATION = 10 * 24 * 60 * 60 * 1000 // 10 days
const val GEOFENCE_DWELL_DELAY = 10 * 1000 // 10 secs // 2 minutes
const val GEOFENCE_LOCATION_REQUEST_CODE = 12345
const val CAMERA_ZOOM_LEVEL = 13f
const val LOCATION_REQUEST_CODE = 123
private val TAG: String = MapsActivity::class.java.simpleName
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var map: GoogleMap
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var geofencingClient: GeofencingClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
geofencingClient = LocationServices.getGeofencingClient(this)
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
map.uiSettings.isZoomControlsEnabled = true
if (!isLocationPermissionGranted()) {
val permissions = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
}
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
LOCATION_REQUEST_CODE
)
} else {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return
}
this.map.isMyLocationEnabled = true
// Zoom to last known location
fusedLocationClient.lastLocation.addOnSuccessListener {
if (it != null) {
with(map) {
val latLng = LatLng(it.latitude, it.longitude)
moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, CAMERA_ZOOM_LEVEL))
}
} else {
with(map) {
moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(65.01355297927051, 25.464019811372978),
CAMERA_ZOOM_LEVEL
)
)
}
}
}
}
setLongClick(map)
setPoiClick(map)
}
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
).showInfoWindow()
// scheduleJob()
}
}
private fun setLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latlng ->
map.addMarker(
MarkerOptions().position(latlng)
.title("Current location")
).showInfoWindow()
map.addCircle(
CircleOptions()
.center(latlng)
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(70, 150, 150, 150))
.radius(GEOFENCE_RADIUS.toDouble())
)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, CAMERA_ZOOM_LEVEL))
val database = Firebase.database
val reference = database.getReference("reminders")
val key = reference.push().key
if (key != null) {
val reminder = Reminder(key, latlng.latitude, latlng.longitude)
reference.child(key).setValue(reminder)
}
createGeoFence(latlng, key!!, geofencingClient)
}
}
private fun createGeoFence(location: LatLng, key: String, geofencingClient: GeofencingClient) {
val geofence = Geofence.Builder()
.setRequestId(GEOFENCE_ID)
.setCircularRegion(location.latitude, location.longitude, GEOFENCE_RADIUS.toFloat())
.setExpirationDuration(GEOFENCE_EXPIRATION.toLong())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
// .setLoiteringDelay(GEOFENCE_DWELL_DELAY)
.build()
val geofenceRequest = GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.addGeofence(geofence)
.build()
val intent = Intent(this, GeofenceReceiver::class.java)
.putExtra("key", key)
.putExtra("message", "Geofence alert - ${location.latitude}, ${location.longitude}")
val pendingIntent = PendingIntent.getBroadcast(
applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(
applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_BACKGROUND_LOCATION
),
GEOFENCE_LOCATION_REQUEST_CODE
)
} else {
geofencingClient.addGeofences(geofenceRequest, pendingIntent)
}
} else {
geofencingClient.addGeofences(geofenceRequest, pendingIntent)
}
}
private fun isLocationPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == GEOFENCE_LOCATION_REQUEST_CODE) {
if (permissions.isNotEmpty() && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"This application needs background location to work on Android 10 and higher",
Toast.LENGTH_SHORT
).show()
}
}
if (requestCode == LOCATION_REQUEST_CODE) {
if (
grantResults.isNotEmpty() && (
grantResults[0] == PackageManager.PERMISSION_GRANTED ||
grantResults[1] == PackageManager.PERMISSION_GRANTED)
) {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
map.isMyLocationEnabled = true
onMapReady(map)
} else {
Toast.makeText(
this,
"The app needs location permission to function",
Toast.LENGTH_LONG
).show()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (grantResults.isNotEmpty() && grantResults[2] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"This application needs background location to work on Android 10 and higher",
Toast.LENGTH_LONG
).show()
}
}
}
}
companion object {
fun removeGeofences(context: Context, triggeringGeofenceList: MutableList<Geofence>) {
val geofenceIdList = mutableListOf<String>()
for (entry in triggeringGeofenceList) {
geofenceIdList.add(entry.requestId)
}
LocationServices.getGeofencingClient(context).removeGeofences(geofenceIdList)
}
fun showNotification(context: Context?, message: String) {
val CHANNEL_ID = "REMINDER_NOTIFICATION_CHANNEL"
var notificationId = 1589
notificationId += Random(notificationId).nextInt(1, 30)
val notificationBuilder = NotificationCompat.Builder(context!!.applicationContext, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_alarm_24)
.setContentTitle(context.getString(R.string.app_name))
.setContentText(message)
.setStyle(
NotificationCompat.BigTextStyle()
.bigText(message)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
context.getString(R.string.app_name),
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = context.getString(R.string.app_name)
}
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(notificationId, notificationBuilder.build())
}
}
// private fun scheduleJob() {
// val componentName = ComponentName(this, ReminderJobService::class.java)
// val info = JobInfo.Builder(321, componentName)
// .setRequiresCharging(false)
// .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
// .setPersisted(true)
// .setPeriodic(15 * 60 * 1000)
// .build()
//
// val scheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
// val resultCode = scheduler.schedule(info)
// if (resultCode == JobScheduler.RESULT_SUCCESS) {
// Log.d(TAG, "Job scheduled")
// } else {
// Log.d(TAG, "Job scheduling failed")
// scheduleJob()
// }
// }
private fun cancelJob() {
val scheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
scheduler.cancel(321)
Log.d(TAG, "Job cancelled")
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5564 次 |
最近记录: |