如何通过全类名设置Kotlin泛型参数?简化多分支实现
解决方案:动态指定Worker类型避免大量分支
核心思路是绕过依赖编译时类型的reified泛型函数,直接使用Worker类的Class对象构建WorkRequest,从而摆脱对when分支的依赖。
方案1:让Work数据类直接携带Worker的Class对象
修改Work类,添加workerClass字段存储对应的Worker类实例,然后直接用该Class对象构建请求:
// 定义Work数据类,携带Worker的Class类型 data class Work( val id: Int, val title: String, val repeatInterval: Long, val repeatIntervalTimeUnit: String, val workerClass: Class<out ListenableWorker> ) object WorkUtils { fun enqueueUniquePeriodicWork(workManager: WorkManager, work: Work) { // 直接传入Class对象,无需分支判断 enqueueUniquePeriodicWorkImpl(workManager, work, work.workerClass) } private fun enqueueUniquePeriodicWorkImpl( workManager: WorkManager, work: Work, workerClass: Class<out ListenableWorker> ) { workManager.enqueueUniquePeriodicWork( work.title, ExistingPeriodicWorkPolicy.UPDATE, // 使用带Class参数的PeriodicWorkRequest.Builder构造方法 PeriodicWorkRequest.Builder( workerClass, work.repeatInterval, TimeUnit.valueOf(work.repeatIntervalTimeUnit) ) .setInputData(workDataOf("workId" to work.id.toString())) .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).build()) .setInitialDelay(10, TimeUnit.MINUTES) .build() ) } }
方案2:通过全类名字符串反射加载Worker类
如果只能拿到Worker的全类名字符串(比如从数据库/配置中读取),可以通过反射动态加载Class对象:
// 定义Work数据类,携带Worker的全类名字符串 data class Work( val id: Int, val title: String, val repeatInterval: Long, val repeatIntervalTimeUnit: String, val workerClassName: String // 格式示例:"com.example.workers.DoSomeThingWork1" ) object WorkUtils { fun enqueueUniquePeriodicWork(workManager: WorkManager, work: Work) { try { // 反射加载Class对象,并强转为ListenableWorker子类 val workerClass = Class.forName(work.workerClassName) as Class<out ListenableWorker> enqueueUniquePeriodicWorkImpl(workManager, work, workerClass) } catch (e: ClassNotFoundException) { // 处理类找不到的异常,如日志记录或默认逻辑 e.printStackTrace() } } private fun enqueueUniquePeriodicWorkImpl( workManager: WorkManager, work: Work, workerClass: Class<out ListenableWorker> ) { // 实现同方案1 workManager.enqueueUniquePeriodicWork( work.title, ExistingPeriodicWorkPolicy.UPDATE, PeriodicWorkRequest.Builder( workerClass, work.repeatInterval, TimeUnit.valueOf(work.repeatIntervalTimeUnit) ) .setInputData(workDataOf("workId" to work.id.toString())) .setConstraints(Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).build()) .setInitialDelay(10, TimeUnit.MINUTES) .build() ) } }
原理说明
原代码中使用的inline fun <reified W> PeriodicWorkRequestBuilder本质是语法糖,内部还是调用了PeriodicWorkRequest.Builder(W::class.java, ...)。直接使用带Class参数的构造方法,就能摆脱编译时泛型的限制,实现动态指定Worker类型,彻底避免编写大量when分支。
内容的提问来源于stack exchange,提问作者SageJustus
相关产品推荐
相关产品推荐

