Wie kann man doppelte Datenbankeinträge verhindern, wenn in Android mehrere regelmäßige Zahlungen mit unterschiedlichen Android

Forum für diejenigen, die für Android programmieren
Guest
 Wie kann man doppelte Datenbankeinträge verhindern, wenn in Android mehrere regelmäßige Zahlungen mit unterschiedlichen

Post by Guest »

Ich möchte dem Benutzer eine reguläre Zahlungsoption hinzufügen. Wenn der Benutzer eine Zahlung in die Datenbank einfügt und die Häufigkeit auf „Täglich“ oder eine andere Option einstellt, basierend auf der Anzahl der verbleibenden Zahlungen, sollten die Daten entsprechend der ausgewählten Häufigkeit hinzugefügt werden. Danach sollten die verbleibenden Zahlungen aktualisiert werden. Wenn der Benutzer eine der täglichen Zahlungen löscht, sollte das System die Zahlung über den regulären Zahlungsplan erneut hinzufügen.
PaymentReceiver

Code: Select all

class PaymentReceiver : BroadcastReceiver() {

companion object {
private val lastExecutionTimes = ConcurrentHashMap()
}

override fun onReceive(context: Context, intent: Intent) {
val title = intent.getStringExtra("TITLE")
val message = intent.getStringExtra("MESSAGE")
val paymentId = intent.getIntExtra("paymentId", 0)
val frequency = intent.getStringExtra("FREQUENCY") ?: return
val currentTime = System.currentTimeMillis()

val userViewModel = UserViewModel(Application.getContext())
val paymentManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

val soundUri = Uri.parse("android.resource://${context.packageName}/raw/notification")

val payment = runBlocking {
userViewModel.getRegularPaymentById(paymentId.toLong())
}

if (payment == null) {
Log.e("PaymentReceiver", "Payment not found for ID: $paymentId")
return
}

if (lastExecutionTimes[paymentId]?.let { currentTime - it < 5000 } == true) {
Log.d("PaymentReceiver", "Duplicate execution avoided for paymentId: $paymentId")
return
}
lastExecutionTimes[paymentId] = currentTime

if (payment?.remainingPayments!! = Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"PAYMENT_CHANNEL",
"Payments",
NotificationManager.IMPORTANCE_HIGH
).apply {
setSound(soundUri, null)
enableVibration(true)
lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
}
paymentManager.createNotificationChannel(channel)
}

val notificationIntent = Intent(context, SplashActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

val pendingIntent = PendingIntent.getActivity(
context,
paymentId,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

val builder = NotificationCompat.Builder(context, "PAYMENT_CHANNEL")
.setSmallIcon(R.mipmap.ic_logo)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_logo))
.setContentTitle(title)
.setContentText(message)
.setSound(soundUri)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setContentIntent(pendingIntent)

paymentManager.notify(paymentId, builder.build())

if (payment?.remainingPayments!! >  0) {
scheduleNextReminder(context, title, message, paymentId, frequency, userViewModel)
}

}

private fun scheduleNextReminder(
context: Context,
title: String?,
message: String?,
paymentId: Int,
frequency: String,
userViewModel: UserViewModel
) {
val nextAlarmTime = calculateNextDueDate(System.currentTimeMillis(), frequency)

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val newIntent = Intent(context, PaymentReceiver::class.java).apply {
putExtra("TITLE", title)
putExtra("MESSAGE", message)
putExtra("paymentId", paymentId)
putExtra("FREQUENCY", frequency)
}

val pendingIntent = PendingIntent.getBroadcast(
context,
paymentId,
newIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

alarmManager.cancel(pendingIntent)

alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
nextAlarmTime,
pendingIntent
)
Log.d("Receiver", "onReceive: *************")
userViewModel.processRegularPayments()
}

private val currentDate: Long get() = resetTimeToZero(System.currentTimeMillis())

private fun calculateNextDueDate(startDate: Long, frequency: String): Long {
val calendar = Calendar.getInstance().apply {
timeInMillis = startDate
}
if (startDate == currentDate) {
return currentDate
}

when (frequency) {
"Daily" -> calendar.add(Calendar.DAY_OF_YEAR, 1)
"Weekly" -> calendar.add(Calendar.WEEK_OF_YEAR, 1)
"Every two weeks" -> calendar.add(Calendar.WEEK_OF_YEAR, 2)
"Monthly" -> calendar.add(Calendar.MONTH, 1)
"Every two months" -> calendar.add(Calendar.MONTH, 2)
"Every three months" -> calendar.add(Calendar.MONTH, 3)
"Every four months" -> calendar.add(Calendar.MONTH, 4)
"Every six months" -> calendar.add(Calendar.MONTH, 6)
"Every year" ->  calendar.add(Calendar.YEAR, 1)
}

return Utils.resetTimeToZero(calendar.timeInMillis)
}

private fun cancelAlarm(context: Context, paymentId: Int) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, PaymentReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context,
paymentId,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
alarmManager.cancel(pendingIntent)
Log.d("PaymentReceiver", "Alarm canceled for paymentId: $paymentId")
}

}
UserViewModel

Code: Select all

class UserViewModel(application: Context) : ViewModel() {

val repository: UserRepository
private val mutex = Mutex()
private var isProcessingPayments = false

init {
val userDao = UserDatabase.getUserDatabase(application).userDao()
repository = UserRepository(userDao)
}

fun getRegularPaymentById(id: Long): RegularPayment? {
return repository.getRegularPaymentById(id)
}

fun getRegularPayments() {
viewModelScope.launch {
_getRegularPayments.value = repository.getAllRegularPayments()
}
}

fun insertOrUpdateRegularPayment(regularPayment: RegularPayment) {
viewModelScope.launch(Dispatchers.IO) {
val paymentId = repository.insertOrUpdateRegularPayment(regularPayment)
regularPayment.id = paymentId
setPayment(Application.getContext(), regularPayment)
}
}

fun setPayment(context: Context, regularPayment: RegularPayment) {

Log.d("UserView", "setPayment: ${regularPayment.id}")

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, PaymentReceiver::class.java).apply {
putExtra("paymentId", regularPayment.id.toInt())
putExtra("TITLE", "Payment Added")
putExtra(
"MESSAGE",
"Added payment: ${regularPayment.paymentName} of ${regularPayment.amount}"
)
putExtra("FREQUENCY", regularPayment.frequency)
}

val pendingIntent = PendingIntent.getBroadcast(
context,
regularPayment.id.toInt(),
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)

if (regularPayment.remainingPayments 
addPaymentToUserData(payment)
}

}
} finally {
isProcessingPayments = false
}
}
}

private fun shouldAddPayment(payment: RegularPayment): Boolean {
val dueDate = calculateNextDueDate(payment.startDate, payment.frequency)
return payment.remainingPayments > 0 &&  dueDate  calendar.add(Calendar.DAY_OF_YEAR, 1)
"Weekly" -> calendar.add(Calendar.WEEK_OF_YEAR, 1)
"Every two weeks" -> calendar.add(Calendar.WEEK_OF_YEAR, 2)
"Monthly" -> calendar.add(Calendar.MONTH, 1)
"Every two months" -> calendar.add(Calendar.MONTH, 2)
"Every three months" -> calendar.add(Calendar.MONTH, 3)
"Every four months" -> calendar.add(Calendar.MONTH, 4)
"Every six months" -> calendar.add(Calendar.MONTH, 6)
"Every year" -> calendar.add(Calendar.YEAR, 1)
}
return resetTimeToZero(calendar.timeInMillis)
}
DAO

Code: Select all

   @Upsert
suspend fun insertOrUpdateRegularPayment(regularPayment: RegularPayment):Long

@Query("SELECT * FROM regular_payment")
suspend fun getAllRegularPayments(): List

@Query("SELECT * FROM regular_payment WHERE id = :id")
fun getRegularPaymentById(id:Long): RegularPayment?

@Query("UPDATE regular_payment SET remainingPayments = :remaining WHERE id = :id")
suspend fun updateRemainingPayments(id: Long, remaining: Int)

@Query("""
SELECT
(SELECT COUNT(*) FROM user_data WHERE regularPaymentID = :paymentId AND expenseName = :paymentName AND date = :date) AS addedCount,
(SELECT COUNT(*) FROM deleted_payment WHERE paymentId = :paymentId AND deleteDate = :date) AS deletedCount
""")
fun isPaymentProcessable(paymentId: Long, paymentName: String, date: Long): ProcessableResult
  • Ich habe versucht, die Verwendung von isProcessingPayments als Flag zu verwalten.
  • Versuchen Sie, den AlarmManager abzubrechen und einen neuen zu starten jedes Mal.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post