问题描述
我正在使用 Google 的地理围栏 API 在我的 geofenceReceiver 类中接收地理围栏事件,但我还需要从我的活动中调用一个方法,所以我想我会在实例化过程中将它作为参数传递。问题是文档仅向您展示了如何使用清单中声明的静态接收器来执行此操作。当我尝试使用意图过滤器,手动注册和取消注册接收器并从 pendingIntent 块发送广播时,块内的代码没有被调用,因此我没有收到任何更新。但是,当通过清单静态声明接收器时,我可以很好地接收更新。我在这里遗漏了一些明显的东西吗?
地理围栏接收器:
class GeofenceReceiver(private val activity: MapsActivity?) : broadcastReceiver() {
private val TAG = GeofenceReceiver::class.java.simpleName
override fun onReceive(context: Context?,intent: Intent?) {
Log.d(TAG,"update received! Activity: $activity")
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceStatusCodes
.getStatusCodeString(geofencingEvent.errorCode)
Log.e(TAG,"error: $errorMessage")
return
}
// Get the transition type.
val geofenceTransition = geofencingEvent.geofenceTransition
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT
) {
// Get the geofences that were triggered. A single event can trigger
// multiple geofences.
val triggeringGeofences = geofencingEvent.triggeringGeofences
val ids = arraylistof<String>()
for (geofence in triggeringGeofences) {
Log.d(TAG,"Geofence ${geofence.requestId} triggered!")
ids.add(geofence.requestId)
}
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
Log.d(TAG,"User entered geofence!")
else {
Log.d(TAG,"User exited geofence!")
//activity.removeGeofences(ids)
}
} else {
// Log the error.
Log.e(TAG,"Invalid transition")
}
}
地图活动:
class MapsActivity : AppCompatActivity(),OnMapReadyCallback {
private var serviceRunning = false
private var mMap: GoogleMap? = null
private var geofenceClient: GeofencingClient? = null
private var geofenceList: ArrayList<Geofence> = arraylistof()
private var markerCirclePairs: MutableMap<String,Pair<Marker,Circle>> = mutableMapOf()
private var currLocationMarker: Marker? = null
private val geofenceReceiver = GeofenceReceiver(this)
private val geofencePendingIntent: PendingIntent by lazy {
val intent = Intent(this,GeofenceReceiver::class.java)
intent.action = "com.spap.geofencepoc.GEOFENCE_EVENT_ACTION"
Log.d("MapsActivity","Pending intent block called")
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
// addGeofences() and removeGeofences().
sendbroadcast(intent)
PendingIntent.getbroadcast(this,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
private val mLocationListener: LocationListener = LocationListener {
currLocationMarker?.remove()
currLocationMarker = mMap?.addMarker(
MarkerOptions().position(LatLng(it.latitude,it.longitude)).title("Current Location")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
)
animateCameraToLocation(currLocationMarker?.position!!)
}
override fun onStart() {
super.onStart()
requestPermissionsIfNeeded()
}
override fun onPause() {
super.onPause()
if (!serviceRunning) {
Intent(this,GeofenceBackgroundService::class.java).also { intent ->
startService(intent)
}
serviceRunning = true
}
(getSystemService(LOCATION_SERVICE) as LocationManager).removeUpdates(mLocationListener)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
val filter = IntentFilter("com.spap.geofencepoc.GEOFENCE_EVENT_ACTION")
registerReceiver(geofenceReceiver,filter)
geofenceClient = LocationServices.getGeofencingClient(this)
// 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)
}
override fun onResume() {
super.onResume()
val mLocationManager = getSystemService(LOCATION_SERVICE) as LocationManager
if (!shouldRequestPermissions()) subscribetoLiveCurrentLocation(mLocationManager)
}
@SuppressLint("MissingPermission")
private fun subscribetoLiveCurrentLocation(mLocationManager: LocationManager) {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,1000,50F,mLocationListener
)
}
private fun requestPermissionsIfNeeded() {
if (!shouldRequestPermissions()) return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
ActivityCompat.requestPermissions(
this,arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),2
)
else ActivityCompat.requestPermissions(
this,1
)
}
private fun shouldRequestPermissions(): Boolean = ContextCompat.checkSelfPermission(
this,Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(
this,Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines,add listeners or move the camera. In this case,* we just add a marker near Sydney,Australia.
* If Google Play services is not installed on the device,the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
mMap?.setonMapClickListener { latlong ->
drawGeofenceOnMap(latlong)
addGeofencetoList(latlong)
}
}
private fun drawGeofenceOnMap(latlong: LatLng) {
val marker = mMap?.addMarker(MarkerOptions().position(latlong).title("Geofence"))
val circle = mMap?.addCircle(
CircleOptions().center(latlong).radius(defaultGeofenceRadius.todouble()).strokeColor(
resources.getColor(android.R.color.holo_red_light,null)
).fillColor(
resources.getColor(android.R.color.transparent,null)
)
)
mMap?.moveCamera(CameraUpdateFactory.newLatLng(latlong))
markerCirclePairs.put("Geofence #${(geofenceList.size + 1)}",Pair(marker!!,circle!!))
}
private fun animateCameraToLocation(latlong: LatLng) {
val cameraPosition = CameraPosition.Builder()
.target(latlong)
.zoom(17f)
.build()
mMap?.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
}
private fun addGeofencetoList(latlong: LatLng) {
geofenceList.add(
Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId("Geofence #" + (geofenceList.size + 1))
// Set the circular region of this geofence.
.setCircularRegion(
latlong.latitude,latlong.longitude,defaultGeofenceRadius
)
// Set the expiration duration of the geofence. This geofence gets automatically
// removed after this period of time.
.setExpirationDuration(10000)
// Set the transition types of interest. Alerts are only generated for these
// transition. We track entry and exit transitions in this sample.
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
// Create the geofence.
.build()
)
}
private fun getGeofencingRequest(): GeofencingRequest {
return GeofencingRequest.Builder().apply {
setinitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
addGeofences(geofenceList)
}.build()
}
private fun addGeofences() {
if (ActivityCompat.checkSelfPermission(
this,Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
Toast.makeText(this,"Need to grant permissions to continue",Toast.LENGTH_LONG).show()
requestPermissionsIfNeeded()
return
}
geofenceClient?.addGeofences(getGeofencingRequest(),geofencePendingIntent)?.run {
addOnSuccessListener {
Toast.makeText(this@MapsActivity,"Geofences added!",Toast.LENGTH_LONG).show()
}
addOnFailureListener {
Toast.makeText(this@MapsActivity,"Failed to add geofences!",Toast.LENGTH_LONG)
.show()
Log.d("MAPSACTIVITY",it.message.toString())
}
}
}
fun removeGeofences(ids: ArrayList<String>) {
removeGeofencesFromClient(ids)
removeGeofencesFromMap(ids)
}
private fun removeGeofencesFromMap(ids: ArrayList<String>) {
for (id in ids) {
if (markerCirclePairs.keys.contains(id)) markerCirclePairs.remove(id)
}
}
private fun removeGeofencesFromClient(ids: ArrayList<String>) {
for (fence in geofenceList) {
if (ids.contains(fence.requestId)) geofenceList.remove(fence)
}
geofenceClient?.removeGeofences(ids)
?.addOnCompleteListener { task ->
if (task.isSuccessful) {
Toast.makeText(
this,"Geofences have been removed!",Toast.LENGTH_LONG
).show()
} else {
Toast.makeText(
this,"Failed to remove geofences",Toast.LENGTH_LONG
).show()
Log.d("MAPSACTIVITY","error ==> " + task.exception)
}
}
}
override fun onDestroy() {
Toast.makeText(this,"activity destroyed!",Toast.LENGTH_SHORT).show()
super.onDestroy()
unregisterReceiver(geofenceReceiver)
mMap = null
geofenceClient = null
serviceRunning = false
stopService(Intent(this,GeofenceBackgroundService::class.java))
}
@SuppressLint("InlinedApi")
override fun onRequestPermissionsResult(
requestCode: Int,permissions: Array<out String>,grantResults: IntArray
) {
var grantFailed = false
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"GRANTED",Toast.LENGTH_SHORT).show()
} else grantFailed = true
}
2 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"GRANTED first",Toast.LENGTH_SHORT).show()
ActivityCompat.requestPermissions(
this,arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),3
)
subscribetoLiveCurrentLocation(getSystemService(LOCATION_SERVICE) as LocationManager)
} else grantFailed = true
}
3 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this,"GRANTED second",Toast.LENGTH_SHORT).show()
subscribetoLiveCurrentLocation(getSystemService(LOCATION_SERVICE) as LocationManager)
} else grantFailed = true
}
}
if (grantFailed) {
if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) ||
shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
) {
Toast.makeText(this,"Show permission rationale",Toast.LENGTH_LONG).show()
} else Toast.makeText(
this,"You must grant the requested permissions to continue",Toast.LENGTH_SHORT
).show()
}
}
override fun onoptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.addGeofence -> {
addGeofences()
true
}
else -> super.onoptionsItemSelected(item)
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.options_menu,menu)
return true
}
}
我按照官方文档在活动的 onCreate() 中注册接收器并在其 onDestroy() 中取消注册,我正在按照适当的命名约定指定一个意图过滤器。尽管以这种方式执行操作时不会调用 pendingIntent 块。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)