Foreground WorkManager Не заканчивает рвботу
Использую workManager для отслеживания передвижения и вести счет таймера, что бы workManager не приостанавливался при блокировке экрана решил выводить все через setForegroundAsync, но когда мне больше не нужен WorkManager процесс не убивается прямым вызовом
@SuppressLint("MissingPermission")
fun startTrackLocation(context: Context) {
val locationWorker =
OneTimeWorkRequestBuilder<TrackLocationWorker>()
.addTag(LOCATION_WORK_TAG)
.build()
WorkManager
.getInstance(context)
.enqueueUniqueWork(
LOCATION_WORK_TAG,
ExistingWorkPolicy.REPLACE,
locationWorker
)
}
fun stopTrackLocation(context: Context) {
Log.e(TAG,"cancel workManager")
repository.stopForeground()
WorkManager.getInstance(context).cancelAllWorkByTag(LOCATION_WORK_TAG)
updateState()
}
Вызов и убийство WorkManager
@HiltWorker
class TrackLocationWorker @AssistedInject constructor(
@Assisted private val context: Context,
@Assisted workerParams: WorkerParameters,
private val repository: RunRepository
) : Worker(context, workerParams) {
private var channelIdFin: String? = null
private lateinit var mFuture: SettableFuture<Result>
private val timer: Timer by lazy { Timer() }
val service: NotificationManager by lazy {
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
private val fusedLocationProvider: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(context)
}
private val callback = object : LocationCallback(){
override fun onLocationResult(locationResult: LocationResult) {
locationResult.locations ?: return
repository.emitLocationFlow(locationResult.lastLocation)
}
}
private fun stopWork(){
//timer.stopTimer()
onStopped()
//WorkManager.getInstance(context).createCancelPendingIntent(id)
}
override fun onStopped() {
Log.e(TAG,"onStopped")
fusedLocationProvider.removeLocationUpdates(callback)
timer.stopTimer()
super.onStopped()
}
@SuppressLint("MissingPermission")
override fun doWork(): Result {
try {
repository.bindForeground { isStart ->
if (isStart) {
timer.startTimer {
repository.emitTimer(it)
setForegroundAsync(getForegroundInfo(it))
}
setForegroundAsync(getForegroundInfo(0L))
} else {
stopWork()
}
}
val locationRequest = LocationRequest.create().apply {
interval = 5000L
fastestInterval = 2000L
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
fusedLocationProvider.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
return Result.success()
} catch (e: Throwable){
return Result.failure()
}
}
private fun getForegroundInfo(milliSeconds: Long): ForegroundInfo {
if (channelIdFin == null) {
channelIdFin =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(service)
} else {
""
}
}
val notificationBuilder = NotificationCompat.Builder(context, channelIdFin!!)
val notification = notificationBuilder
.setAutoCancel(true)
.setSmallIcon(R.drawable.planet)
.setContentTitle(milliSeconds.returnTimeWithoutMilliSecondsFromMilliseconds())
.setSubText(RUN)
.build()
//service.notify(101,notification)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(102, notification, FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
ForegroundInfo(102, notification)
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(service: NotificationManager): String{
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH).also {
it.lightColor = context.getColor(R.color.purple_700)
it.importance = NotificationManager.IMPORTANCE_NONE
service.createNotificationChannel(it)
}
return channelId
}
Сам WorkManager
//workManager
implementation "android.arch.work:work-runtime-ktx:1.0.1"
Версия WorkManager (Возможно проблема в ней, но заметил когда ставишь другую Hilt не хочет ее находить, хотя все правила соблюденыы)
@HiltAndroidApp
class App: Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: RunWorkerFactory
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
}
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
class RunWorkerFactory @Inject constructor(
private val repository: RunRepository
): WorkerFactory() {
override fun createWorker(
appContext: Context,
workerClassName: String,
workerParameters: WorkerParameters
): ListenableWorker {
return TrackLocationWorker(appContext,
workerParameters,
repository
)
}
}
Ответы (1 шт):
Автор решения: Svetl9chok
→ Ссылка
@HiltWorker
class TrackLocationWorker @AssistedInject constructor(
@Assisted private val context: Context,
@Assisted workerParams: WorkerParameters,
private val repository: RunRepository
) : ListenableWorker (context, workerParams) {
private var channelIdFin: String? = null
private lateinit var mFuture: SettableFuture<Result>
private val timer: Timer by lazy { Timer() }
val notificationManager: NotificationManager by lazy {
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
private val fusedLocationProvider: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(context)
}
private val callback = object : LocationCallback(){
override fun onLocationResult(locationResult: LocationResult) {
locationResult.locations ?: return
repository.emitLocationFlow(locationResult.lastLocation)
}
}
@SuppressLint("RestrictedApi")
private fun stopWork(){
Log.e(TAG,"stopWork")
fusedLocationProvider.removeLocationUpdates(callback)
timer.stopTimer()
mFuture.set(Result.success())
}
private fun getForegroundInfo(): ForegroundInfo {
if (channelIdFin == null) {
channelIdFin =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(notificationManager)
} else {
""
}
}
val intent = PendingIntent.getActivity(
context,
0,
Intent(context, RunActivity::class.java).putExtra(Constant.FROM_WORKMANAGER,true),
0
)
val notificationBuilder = NotificationCompat.Builder(context, channelIdFin!!)
.setAutoCancel(false)
.setSmallIcon(R.drawable.planet)
.setContentTitle("00:00")
.setSubText(RUN)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(intent)
val foregroundInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(NOTIFICATION_ID, notificationBuilder.build(), FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
ForegroundInfo(NOTIFICATION_ID, notificationBuilder.build())
}
timer.startTimer {
repository.emitTimer(it)
notificationBuilder.setContentTitle(it.returnTimeWithoutMilliSecondsFromMilliseconds())
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
}
return foregroundInfo
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(service: NotificationManager): String{
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH).also {
it.lightColor = context.getColor(R.color.purple_700)
it.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
service.createNotificationChannel(it)
}
return channelId
}
@SuppressLint("MissingPermission", "RestrictedApi")
override fun startWork(): ListenableFuture<Result> {
mFuture = SettableFuture.create()
try {
repository.bindForeground { isStart ->
if (isStart) {
setForegroundAsync(getForegroundInfo())
} else {
stopWork()
}
}
val locationRequest = LocationRequest.create().apply {
interval = 5000L
fastestInterval = 2000L
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
fusedLocationProvider.requestLocationUpdates(locationRequest, callback, Looper.getMainLooper())
// mFuture.set(Result.success())
} catch (e: Throwable){
mFuture.set(Result.failure())
}
return mFuture
}
override fun onStopped() {
Log.e(TAG,"onStooped")
super.onStopped()
}
}
Переписав свой Worker поменяв его на ListenableWorker и вызывав mFuture.set(Result.success()) по окнчанию работы я добился поведение которое мне нужно