当应用程序不在前台时,无法使用 PeriodicWorkRequest 在会议室数据库中插入数据

Unable to Insert Data in the Room Database Using PeriodicWorkRequest When App is Not in the Foreground

提问人:Kalpesh Doru 提问时间:11/8/2023 最后编辑:Kalpesh Doru 更新时间:11/9/2023 访问量:34

问:

当我的 Android 应用程序不在前台时,我遇到了使用 PeriodicWorkRequest 将数据插入数据库的问题。我设置了一个 Room 数据库、Hilt 和 WorkManager 来执行此任务。下面是相关代码和配置:

依赖:

implementation 'androidx.room:room-runtime:2.4.0'
implementation 'androidx.room:room-ktx:2.4.0'
kapt 'androidx.room:room-compiler:2.4.0'
implementation 'com.google.dagger:hilt-android:2.44'
kapt 'com.google.dagger:hilt-compiler:2.44'
kapt 'androidx.hilt:hilt-compiler:1.0.0'
implementation 'androidx.work:work-runtime-ktx:2.8.1'
implementation 'androidx.hilt:hilt-work:1.1.0'

我还在AndroidManifest.xml中定义了一个提供程序:

<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    tools:node="remove" />

这是我的 Application 类:

@HiltAndroidApp
class App : Application(), Configuration.Provider {
    @Inject
    lateinit var workerFactory: HiltWorkerFactory

    override fun getWorkManagerConfiguration(): Configuration {
        return Configuration.Builder()
            .setMinimumLoggingLevel(Log.DEBUG)
            .setWorkerFactory(workerFactory)
            .build()
    }
}

我设置了一个 Hilt 模块:

@InstallIn(SingletonComponent::class)
@Module
class DeviceModule {
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext context: Context): AppDatabase {
        return Room.databaseBuilder(
            context, AppDatabase::class.java, Constant.DATABASE_NAME
        )
            .addCallback(object : RoomDatabase.Callback() {
                override fun onCreate(db: SupportSQLiteDatabase) {
                    super.onCreate(db)
                    val request = OneTimeWorkRequestBuilder<LocationWorker>().build()
                    WorkManager.getInstance(context).enqueue(request)
                }
            })
            .build()
    }

    @Provides
    fun provideDeviceDao(appDatabase: AppDatabase): DeviceDao {
        return appDatabase.deviceDao()
    }
}

我使用抽象类绑定了实现:

@Module
@InstallIn(SingletonComponent::class)
abstract class DeviceBind {
    @Binds
    @Singleton
    abstract fun deviceBind(deviceRepoImpl: DeviceRepoImpl): DeviceRepo
}

我的 AppDatabase 类:

@Database(entities = [DeviceModel::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
    abstract fun deviceDao(): DeviceDao
}

DeviceDao 接口:

@Dao
interface DeviceDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun addDevice(deviceModel: DeviceModel)

    @Query("SELECT * FROM ${Constant.QUESTION_TABLE}")
    fun getDevice(): Flow<MutableList<DeviceModel>>

    @Query("DELETE FROM ${Constant.QUESTION_TABLE}")
    suspend fun truncate()
}

我的仓库接口及其实现:

interface DeviceRepo {
    suspend fun addDevice(deviceModel: DeviceModel)
    suspend fun getDevice(): Flow<Resource<MutableList<DeviceModel>>>
    suspend fun truncate()
}

class DeviceRepoImpl @Inject constructor(private val deviceDao: DeviceDao) : DeviceRepo {
    override suspend fun addDevice(deviceModel: DeviceModel) {
        deviceDao.addDevice(deviceModel)
    }

    override suspend fun getDevice(): Flow<Resource<MutableList<DeviceModel>>> = flow {
        emit(Resource.Loading())
        deviceDao.getDevice().catch {
            emit(Resource.Error("Something went wrong"))
        }.collect {
            emit(Resource.Success(it))
        }
    }

    override suspend fun truncate() {
        deviceDao.truncate()
    }
}

我的仓库接口及其对 Location 的实现:

interface LocationClient {
    suspend fun getLocation(context: Context, interval: Long): Location
    class LocationException(message: String) : Exception()
}

class LocationClientImpl @Inject constructor(
    private val client: FusedLocationProviderClient
) : LocationClient {

    @SuppressLint("MissingPermission")
    override suspend fun getLocation(context: Context, interval: Long): Location {
        if (!context.hasLocationPermission()) {
            throw LocationClient.LocationException("Missing location permission")
        }

        val locationManager =
            context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
        val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
        val isNetworkEnabled =
            locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
        if (!isGpsEnabled && !isNetworkEnabled) {
            throw LocationClient.LocationException(message = "GPS is disabled")
        }

        val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
            .setWaitForAccurateLocation(false)
            .build()

        return suspendCancellableCoroutine { continuation ->
            val locationCallback = object : LocationCallback() {
                override fun onLocationResult(result: LocationResult) {
                    super.onLocationResult(result)
                    result.locations.lastOrNull()?.let { location ->
                        client.removeLocationUpdates(this)
                        continuation.resume(location)
                    }
                }

                override fun onLocationAvailability(availability: LocationAvailability) {
                    super.onLocationAvailability(availability)
                    if (!availability.isLocationAvailable) {
                        client.removeLocationUpdates(this)
                        continuation.resumeWithException(LocationClient.LocationException("Location not available"))
                    }
                }
            }

            client.requestLocationUpdates(request, locationCallback, Looper.getMainLooper())
        }
    }
}

我还有一个用于后台工作的 worker 类:

@HiltWorker
class LocationWorker @AssistedInject constructor(
    @Assisted var context: Context,
    @Assisted parameters: WorkerParameters,
    private var locationClient: LocationClient,
    private val deviceRepo: DeviceRepo
) :
    CoroutineWorker(context, parameters) {
    private val TAG = "LocationWorker"
    override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
        try {
            val location = locationClient.getLocation(context, 1000L)
            val deviceModel = DeviceModel(
                longitude = location.longitude,
                latitude = location.latitude,
                time = location.time,
                accuracy = location.accuracy
            )
            deviceRepo.addDevice(deviceModel)
            createNotification(context, location)
            Result.success()
        } catch (e: Exception) {
            Log.d(TAG, "Exception: ${e.message}")
            NotificationHandler.createNotification(context = context, "${e.message}", "${e.stackTrace}")
            Result.failure()
        }
    }

    private fun createNotification(context: Context, location: Location? = null) {
        NotificationHandler.createNotification(
            context = context,
            title = "Hi from Location",
            "Lat: ${location?.latitude}\n" +
                    "Long: ${location?.accuracy}\n" +
                    "Accuracy: ${location?.accuracy}"
        )
    }
}

工作请求

val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build()
    val workManager = WorkManager.getInstance(this@MainActivity)
    val request: PeriodicWorkRequest =
        PeriodicWorkRequestBuilder<LocationWorker>(1, TimeUnit.HOUR).setConstraints(constraints)
            .build()
    workManager.enqueueUniquePeriodicWork(
    "reminder_notification_work",
    ExistingPeriodicWorkPolicy.UPDATE,request)
    workManager.getWorkInfosForUniqueWorkLiveData("reminder_notification_work")
    .observe(lifecycleOwner)
    {
        workInfo ->
        workInfo.forEach {
            workManagerState.value = it.state.toString()
        }
    }

尽管进行了所有这些设置,但当应用不在前台时,数据插入不起作用。任何指导或建议将不胜感激。谢谢!

Android 地理位置 dagger-hilt android-workmanager

评论


答: 暂无答案