You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现适配Android ActionCallback的无参构造通用基类

问题

我有4个继承自ActionCallback的类,代码逻辑高度相似,仅在运行时需实例化不同的Object(ObjectA-D)与MyClass(MyClassA-D)。原本可通过传参创建对应对象与类,但受Android ActionCallback特性限制,无法向Action类传递参数。现希望实现类似GenericAction的通用基类,作为单一可信源,避免重复编写4个Action类,请教最优实现方式。

原重复代码示例:

class ActionA : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        doSomething(context, ObjectA, glanceId)
        val constructSomething = MyClassA(context)
    }
}

class ActionB : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        doSomething(context, ObjectB, glanceId)
        val constructSomething = MyClassB(context)
    }
}

class ActionC : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        doSomething(context, ObjectC, glanceId)
        val constructSomething = MyClassC(context)
    }
}

class ActionD : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        doSomething(context, ObjectD, glanceId)
        val constructSomething = MyClassD(context)
    }
}

尝试的通用类(存在实例化参数问题):

class GenericAction<T>(myObject: Any, myClazz: Class<T>) : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        doSomething(context, myObject, glanceId)
        val constructSomething = myClazz<T>(context)
    }
}

最优实现方案

方案1:枚举封装+泛型基类(类型安全首选)

因为Android要求ActionCallback必须有无参构造,我们可以用枚举封装每个Action需要的依赖逻辑,再通过静态内部类实现无参构造的要求,同时把核心逻辑统一到基类中。

步骤1:统一基类与枚举定义

先给MyClassA-D定义共同基类,再用枚举封装每个Action的专属依赖:

// 给MyClass系列定义抽象基类,统一类型
abstract class BaseMyClass(context: Context)
class MyClassA(context: Context) : BaseMyClass(context)
class MyClassB(context: Context) : BaseMyClass(context)
class MyClassC(context: Context) : BaseMyClass(context)
class MyClassD(context: Context) : BaseMyClass(context)

// 枚举封装每个Action需要的Object对象和MyClass构造逻辑
enum class ActionType(
    val targetObject: Any,
    val myClassCreator: (Context) -> BaseMyClass
) {
    TYPE_A(ObjectA) { context -> MyClassA(context) },
    TYPE_B(ObjectB) { context -> MyClassB(context) },
    TYPE_C(ObjectC) { context -> MyClassC(context) },
    TYPE_D(ObjectD) { context -> MyClassD(context) }
}

步骤2:实现通用ActionCallback基类

通过私有构造+静态内部类的方式,满足Android无参构造要求,同时复用核心逻辑:

class GenericAction private constructor(private val actionType: ActionType) : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        // 复用共同逻辑
        doSomething(context, actionType.targetObject, glanceId)
        val constructSomething = actionType.myClassCreator(context)
        // 后续可统一处理constructSomething的逻辑
    }

    // 为每个ActionType生成无参子类,直接用于Android组件绑定
    class ActionA : GenericAction(ActionType.TYPE_A)
    class ActionB : GenericAction(ActionType.TYPE_B)
    class ActionC : GenericAction(ActionType.TYPE_C)
    class ActionD : GenericAction(ActionType.TYPE_D)
}

使用时直接引用GenericAction.ActionA、GenericAction.ActionB即可,后续新增类型只需在枚举中添加项,再新增一个对应静态内部类,完全避免重复代码。

方案2:ActionParameters传递标识(动态场景可选)

如果允许在触发Action时传递参数,可以通过ActionParameters传入类型标识,在通用Action中分支处理:

class GenericAction : ActionCallback {
    override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
        val actionType = parameters[KEY_ACTION_TYPE] ?: return
        
        // 获取对应Object
        val targetObject = when(actionType) {
            "TYPE_A" -> ObjectA
            "TYPE_B" -> ObjectB
            "TYPE_C" -> ObjectC
            "TYPE_D" -> ObjectD
            else -> return
        }
        doSomething(context, targetObject, glanceId)

        // 实例化对应MyClass
        val constructSomething = when(actionType) {
            "TYPE_A" -> MyClassA(context)
            "TYPE_B" -> MyClassB(context)
            "TYPE_C" -> MyClassC(context)
            "TYPE_D" -> MyClassD(context)
            else -> return
        }
        // 后续逻辑
    }

    companion object {
        val KEY_ACTION_TYPE = ActionParameters.Key<String>("action_type")
        // 触发Action时传入参数:actionParametersOf(KEY_ACTION_TYPE to "TYPE_A")
    }
}

这种方式无需创建多个子类,但依赖参数传递,类型安全稍弱,适合类型可能动态调整的场景。


方案对比

  • 方案1:类型安全、代码整洁,维护成本低,适合类型固定、不频繁新增的场景。
  • 方案2:无需多子类,灵活性高,但类型校验依赖运行时,适合动态场景。

内容的提问来源于stack exchange,提问作者mars8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:05:31