WorkManager

本文介绍了如何使用Kotlin和WorkManager在Android应用中创建周期性任务,结合Retrofit进行网络请求,并根据时间窗口进行调度。作者展示了如何设置约束条件、时间间隔以及如何在满足特定工作时间时执行任务。
摘要由CSDN通过智能技术生成

fun setupPolling() {
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresDeviceIdle(false)
        .setRequiresCharging(false)
        .build()

    val daysOfWeek = listOf(
        DayOfWeek.MONDAY,
        DayOfWeek.TUESDAY,
        DayOfWeek.WEDNESDAY,
        DayOfWeek.THURSDAY,
        DayOfWeek.FRIDAY
    )

    val timeWindowStart = TimeOfDay(9, 10)
    val timeWindowEndMorning = TimeOfDay(11, 20)
    val timeWindowStartAfternoon = TimeOfDay(13, 10)
    val timeWindowEnd = TimeOfDay(17, 20)

    val periodStartTime = PeriodicWorkRequest.calculateNextRunTime(
        FlexTimeInterval.Builder()
            .setDaysOfWeek(daysOfWeek)
            .setStartTime(timeWindowStart)
            .setEndTime(timeWindowEnd)
            .addInterval(TimeInterval=timeWindowStartAfternoon.timeIntervalSince(timeWindowEndMorning))
            .build(),
        System.currentTimeMillis(),
        TimeUnit.MINUTES.toMillis(1)
    )

    val pollingRequest = PeriodicWorkRequestBuilder<PollingWorker>(1, TimeUnit.MINUTES)
        .setConstraints(constraints)
        .setInitialDelay(periodStartTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
        .build()

    WorkManager.getInstance().enqueueUniquePeriodicWork("polling_work", ExistingPeriodicWorkPolicy.REPLACE, pollingRequest)
}

 

 

 

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2" // 或者其他版本
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2" // 如果你在Android上
implementation "androidx.work:work-runtime-ktx:2.7.0" // WorkManager
implementation "com.squareup.retrofit2:retrofit:2.9.0" // Retrofit
implementation "com.squareup.retrofit2:converter-gson:2.9.0" // 如果使用Gson作为转换器
 

 

 

class PollingWork(appContext: Context, params: WorkerParameters) :
    Worker(appContext, params) {

    private val api: MyApi by lazy {
        retrofit.create(MyApi::class.java)
    }

    override fun doWork(): Result {
        return try {
            val currentTime = System.currentTimeMillis()
            if (isWeekdayMorning(currentTime) || isWeekdayAfternoon(currentTime)) {
                val data = api.fetchData()
                // 处理获取到的数据
                Result.success()
            } else {
                // 如果不是工作时间,则提前结束WorkRequest
                Result.retry()
            }
        } catch (e: Exception) {
            // 处理异常
            Result.retry()
        }
    }

    private fun isWeekdayMorning(time: Long): Boolean {
        val calendar = Calendar.getInstance()
        calendar.timeInMillis = time
        return calendar.get(Calendar.DAY_OF_WEEK) in 1..5 &&
            time >= 9 * 60 * 1000 && time < 11 * 60 * 1000 + 20 * 60 * 1000
    }

    private fun isWeekdayAfternoon(time: Long): Boolean {
        val calendar = Calendar.getInstance()
        calendar.timeInMillis = time
        return calendar.get(Calendar.DAY_OF_WEEK) in 1..5 &&
            time >= 13 * 60 * 1000 && time < 17 * 60 * 1000 + 20 * 60 * 1000
    }
}
 

 

val workRequest = OneTimeWorkRequest.Builder(PollingWork::class.java)
    .build()
WorkManager.getInstance(context).enqueue(workRequest)
 

class PollingJobService : JobService() {

    private val apiService: ApiService by lazy {
        val retrofit = Retrofit.Builder()
            .baseUrl("https://your-api-url.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        retrofit.create(ApiService::class.java)
    }

    override fun onStartJob(params: JobParameters?): Boolean {
        doPollingTask(params!!)
        return true
    }

    private fun doPollingTask(jobParameters: JobParameters) {
        val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

        val jobId = jobParameters.jobId
        val workTimeIntervals = listOf(
            Pair(Calendar.MONDAY, Pair(9, 10)), // 9:10 AM
            Pair(Calendar.MONDAY, Pair(13, 10)), // 1:10 PM
            Pair(Calendar.FRIDAY, Pair(17, 20))   // 5:20 PM for Friday (you need to add other weekdays too)
        )

        if (isWithinWorkTimeInterval(workTimeIntervals)) {
            apiService.getData().enqueue(object : Callback<YourDataType> {
                override fun onResponse(call: Call<YourDataType>, response: Response<YourDataType>) {
                    // Handle the response here
                }

                override fun onFailure(call: Call<YourDataType>, t: Throwable) {
                    // Handle error here
                }
            })
        }

        jobFinished(jobParameters, false)
        scheduleNextJob(jobScheduler, jobId)
    }

    private fun isWithinWorkTimeInterval(intervals: List<Pair<Int, Pair<Int, Int>>>): Boolean {
        val calendar = Calendar.getInstance()
        val hour = calendar.get(Calendar.HOUR_OF_DAY)
        val minute = calendar.get(Calendar.MINUTE)
        val dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)

        for ((day, time) in intervals) {
            if (day == dayOfWeek && time.first <= hour && hour < time.second) {
                return true
            }
        }
        return false
    }

    private fun scheduleNextJob(jobScheduler: JobScheduler, jobId: Int) {
        // Schedule your next job based on your requirement
        // For example, every minute within the specified time interval.
        // Here we are not scheduling the exact minute-based poll but just a sample.
        val jobInfo = JobInfo.Builder(jobId, ComponentName(this, PollingJobService::class.java))
            .setPeriodic(60 * 1000) // Every minute
            .build()

        jobScheduler.schedule(jobInfo)
    }

    override fun onStopJob(params: JobParameters?): Boolean {
        // You may want to reschedule the job if it was stopped before completion
        return false
    }
}
 

<service

    android:name=".MyJobService"

    android:permission="android.permission.BIND_JOB_SERVICE"/>

 
 
import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.util.Log
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import java.lang.Exception
import java.util.concurrent.TimeUnit
 
 
class PeriodicJobService: JobService() {
 
 
    private suspend fun Count(): Flow<Int> {
        return flow {
            for(i in 200..210){
                delay(100)
                emit(i)
            }
        }
    }
 
 
    override fun onStartJob(p0: JobParameters?): Boolean {
        val resScope = CoroutineScope(Job())
        resScope.launch {
            try {
                Count().flowOn(Dispatchers.IO).collect {
                    Log.i(TAG, "collect $it")
                }
                Log.i(TAG, "jobFinished")
            }catch (e: Exception){
                e.printStackTrace()
                Log.e(TAG, e.message.toString())
            }
        }
        startScheduler(this)
        return false
    }
 
 
    override fun onStopJob(p0: JobParameters?): Boolean = false
 
 
    companion object {
 
 
        var TAG: String = "taskjob"
        var JOBID : Int = 100
        var InterValTime :Long = 10000
        private var jobScheduler: JobScheduler? = null
        private var jobInfo: JobInfo? = null
 
 
        fun startScheduler(context: Context) {
            jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
            cancelScheduler()
            if (jobInfo == null) {
                jobInfo = JobInfo.Builder(JOBID, ComponentName(context, PeriodicJobService::class.java))
                    .setMinimumLatency(InterValTime) // 最小为10秒
                    .build()
            }
            val result = jobScheduler?.schedule(jobInfo!!)
        }
 
 
        fun cancelScheduler() {
            jobScheduler?.cancel(JOBID)
        }
    }
}

 

import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobScheduler
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import android.util.Log
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class PollingJobService : JobService() {

    private lateinit var retrofit: Retrofit
    private lateinit var apiService: MyApiService

    override fun onStartJob(params: JobParameters): Boolean {
        // 初始化Retrofit
        retrofit = Retrofit.Builder()
            .baseUrl("https://your-api-base-url.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        apiService = retrofit.create(MyApiService::class.java)

        // 发起网络请求
        apiService.fetchData().enqueue(object : Callback<YourDataType> {
            override fun onResponse(call: Call<YourDataType>, response: Response<YourDataType>) {
                // 处理你的数据
                Log.d("PollingJobService", "Received data: ${response.body()}")

                // 检查是否还需要继续轮询
                if (shouldContinuePolling()) {
                    scheduleNextJob()
                }
            }

            override fun onFailure(call: Call<YourDataType>, t: Throwable) {
                // 处理网络请求失败的情况
                Log.e("PollingJobService", "Failed to fetch data", t)

                // 检查是否还需要继续轮询
                if (shouldContinuePolling()) {
                    scheduleNextJob()
                }
            }
        })

        return true // 表示任务已完成,不需要重新调度
    }

    override fun onStopJob(params: JobParameters): Boolean {
        // 停止轮询
        return true
    }

    private fun shouldContinuePolling(): Boolean {
        // 实现你的逻辑来判断是否应该继续轮询
        // 例如,检查当前时间是否在上午9:10到11:20或下午13:10到17:20之间
        // 并且是周一到周五
        val currentTime = // 获取当前时间
        // 实现你的时间判断逻辑
        return // 返回true如果应该继续轮询,否则返回false
    }

    private fun scheduleNextJob() {
        // 安排下一个轮询任务
        val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

        val jobInfo = JobInfo.Builder(
            JOB_ID, // 唯一标识符
            ComponentName(this, PollingJobService::class.java)
        ).setMinimumLatency(1, TimeUnit.MINUTES) // 设置最小延迟
        // 添加其他调度参数,比如只在工作日特定时间运行等

        jobScheduler.schedule(jobInfo.build())
    }

    companion object {
        const val JOB_ID = 1000 // 自定义的任务ID
    }
}
 

 

 

 

 

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值