Как получить правильную информацию о переходе через Geofence?

Я работал над приложением, которое регистрирует информацию о геозоне в текстовом файле при пересечении периметра. По какой-то причине всегда принимает имя первого значения в моем массиве напоминаний Geofence, а не то, которое было пересечено. Я не могу найти ничего другого в Интернете, что отвечает на этот вопрос в любом качестве.

Вот код для ReminderRepository.kt:

class ReminderRepository(private val context: Context) {

  companion object {
    private const val PREFS_NAME = "ReminderRepository"
    private const val REMINDERS = "REMINDERS"
  }

  private val preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
  private val gson = Gson()
  private val geofencingClient = LocationServices.getGeofencingClient(context)

    private val geofencePendingIntent: PendingIntent by lazy {
        val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
        PendingIntent.getBroadcast(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT)
    }


    fun add(reminder: Reminder, success: () -> Unit, failure: (error: String) -> Unit) {
        val geofence = buildGeofence(reminder)
        if (geofence != null
            && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            geofencingClient.addGeofences(buildGeofencingRequest(geofence), geofencePendingIntent)
                .addOnSuccessListener {
                    saveAll(getAll() + reminder)
                    success()
                }.addOnFailureListener {
                    failure(GeofenceErrorMessages.getErrorString(context, it))
                }
        }
    }


  private fun buildGeofence(reminder: Reminder): Geofence? {
    val latitude = reminder.latLng?.latitude
    val longitude = reminder.latLng?.longitude
    val radius = reminder.radius

    if (latitude != null && longitude != null && radius != null) {
      return Geofence.Builder()
          .setRequestId(reminder.id)
          .setCircularRegion(
              latitude,
              longitude,
              radius.toFloat()
          )
          .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT) // 12/01 - MAJOR necessary addition :x
          .setExpirationDuration(Geofence.NEVER_EXPIRE)
          .build()
    }
    return null
  }

    private fun buildGeofencingRequest(geofence: Geofence): GeofencingRequest {
        return GeofencingRequest.Builder()
            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
            .addGeofences(listOf(geofence))
            .build()
    }


    fun remove(reminder: Reminder, success: () -> Unit, failure: (error: String) -> Unit) {
    geofencingClient
        .removeGeofences(listOf(reminder.id)).addOnSuccessListener {
          saveAll(getAll() - reminder)
          success()
        }.addOnFailureListener {
          failure(GeofenceErrorMessages.getErrorString(context, it))
        }
  }

  private fun saveAll(list: List<Reminder>) {
    preferences.edit().putString(REMINDERS, gson.toJson(list)).apply()
  }

  fun getAll(): List<Reminder> {
    if (preferences.contains(REMINDERS)) {
      val remindersString = preferences.getString(REMINDERS, null)
      val arrayOfReminders = gson.fromJson(remindersString, Array<Reminder>::class.java)

      if (arrayOfReminders != null) {
        return arrayOfReminders.toList()
      }
    }
    return listOf()
  }

  fun get(requestId: String?) = getAll().firstOrNull { it.id == requestId }
  fun getLast() = getAll().lastOrNull()
}

ReminderApp.kt:

class ReminderApp : Application() {

  private lateinit var repository: ReminderRepository

  override fun onCreate() {
    super.onCreate()
    repository = ReminderRepository(this)
  }

  fun getRepository() = repository
}

GeofenceBroadcastReceiver.kt:

class GeofenceBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
    }
}

Вот код файла GeofenceTransitionsJobIntentService.kt:

    // The file name is saved in ../res/values/strings.xml
    val fileName = "fencelog.txt"
    val lineBreak: String? = System.getProperty("line.separator")

    companion object {
        private const val LOG_TAG = "GeoTrIntentService"
        private const val JOB_ID = 573

        fun enqueueWork(context: Context, intent: Intent) {
            enqueueWork(context, GeofenceTransitionsJobIntentService::class.java, JOB_ID, intent)
        }
    }

    @RequiresApi(Build.VERSION_CODES.O)
    override fun onHandleWork(intent: Intent) {
        val geofencingEvent = GeofencingEvent.fromIntent(intent)
        if (geofencingEvent.hasError()) {
            val errorMessage = GeofenceErrorMessages.getErrorString(this, geofencingEvent.errorCode)
            Log.e(LOG_TAG, errorMessage)
            return
        }
        handleEvent(geofencingEvent)
    }

    // Handle what happens when a transition is received
    @RequiresApi(Build.VERSION_CODES.O)
    private fun handleEvent(event: GeofencingEvent) {
        if (event.geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
            // Get the reminder for the entered Geofence and get its message and coordinate values
            val reminder = getFirstReminder(event.triggeringGeofences)
            val message = reminder?.message
            val latLng = reminder?.latLng

            // Ensure neither reminder.message nor reminder.latLng is null
            if (message != null && latLng != null) {
                // Record the transition in fencelog.txt and send the user a notification alerting them to their arrival
                writeToLogFile(this, fileName, message, getTimeStamp(), true)
                sendNotification(this, "You've arrived at $message!", latLng)
            }
        }

        if (event.geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
            val reminder = getFirstReminder(event.triggeringGeofences)
            val message = reminder?.message
            val latLng = reminder?.latLng

            if (message != null && latLng != null) {
                sendNotification(this, "You just left $message!", latLng)
                writeToLogFile(this, fileName, message, "some time", false)
            }
        }
    }

    // Get the reminder that was used to create the Geofence
    private fun getFirstReminder(triggeringGeofences: List<Geofence>): Reminder? {
        val firstGeofence = triggeringGeofences[0]
        return (application as ReminderApp).getRepository().get(firstGeofence.requestId)
    }

Скажем, у меня есть три местоположения в моем списке геозон — местоположение A, местоположение B и местоположение C — в позициях 0, 1 и 2 соответственно. Если я войду в какое-либо из этих местоположений, появится сообщение о том, что я вошел в местоположение А, независимо от того, где я на самом деле нахожусь, потому что программа извлекает данные для местоположения А при регистрации.

Нужно ли что-то менять в функции getFirstReminder? Есть ли лучший способ сделать это в целом? Я вижу, что функция, кажется, буквально берет первый элемент в массиве, что и вызывает проблему, но я не знаю, чем его заменить, чтобы он функционировал должным образом.


person ADO    schedule 04.12.2019    source источник


Ответы (1)


попробуйте этот исходный код git hub, он находится в kotlin https://github.com/exozet/Geolocator

person reza kia    schedule 12.05.2020