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

Kotlin Jetpack Compose:迁移Braintree代码至独立类遇DropInListener/AppCompatActivity错误

解决方案:解耦Braintree代码与Activity依赖

要实现Braintree代码的独立封装,同时避免强制继承AppCompatActivity,核心是通过依赖传递替代直接依赖Activity实例,具体实现如下:

1. 封装独立的Braintree管理类

创建BraintreeManager类,通过构造函数传入所需的上下文、仓库实例和回调监听器,完全脱离对Activity的继承依赖:

class BraintreeManager(
    private val activity: AppCompatActivity,
    private val commonRepository: CommonRepository,
    private val dropInListener: DropInListener
) {
    private lateinit var dropInClient: DropInClient
    private lateinit var braintreeClient: BraintreeClient
    private lateinit var dataCollector: DataCollector

    init {
        initClients()
    }

    private fun initClients() {
        dropInClient = DropInClient(activity, ExampleClientTokenProvider(commonRepository))
        dropInClient.setListener(dropInListener)
        braintreeClient = BraintreeClient(activity, CLIENT_TOKEN)
        dataCollector = DataCollector(braintreeClient)
    }

    fun loadDropIn() {
        val dropInRequest = DropInRequest()
        dropInClient.launchDropIn(dropInRequest)
    }

    fun collectDeviceData(paymentMethodNonce: String?) {
        dataCollector.collectDeviceData(activity) { deviceData, error ->
            val deviceDataObj = Gson().fromJson(deviceData, DeviceData::class.java)
            CoroutineScope(Dispatchers.IO).launch {
                paymentMethodNonce?.let {
                    commonRepository.checkout(
                        commonRepository.amount,
                        commonRepository.uuid,
                        it,
                        deviceDataObj.correlation_id
                    )
                }
            }
        }
    }
}

2. 改造MainActivity

让MainActivity继续实现DropInListener,并在内部实例化BraintreeManager,将自身作为上下文、监听器传递,同时保留权限请求逻辑(权限属于Activity范畴,无需迁移):

@AndroidEntryPoint
class MainActivity : AppCompatActivity(), DropInListener {
    @Inject lateinit var commonRepository: CommonRepository
    private lateinit var braintreeManager: BraintreeManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            // 原有Compose内容保持不变
            val navController = rememberNavController()
            SnoozeForGoodTheme(false) {
                // 权限检查逻辑保留在Activity中
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                    checkPermission(SCHEDULE_EXACT_ALARM, 1)
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    checkPermission(USE_EXACT_ALARM, 1)
                }
                checkPermission(RECEIVE_BOOT_COMPLETED, 1)
                checkPermission(INTERNET, 1)

                NavHost(
                    navController = navController, 
                    startDestination = SplashDirections.root.destination
                ) {
                    composable(route = SplashDirections.root.destination) {
                        Log.d("TAG2", "going splash page")
                        SplashContentFactory().Content(navController)
                    }
                }
            }
        }

        // 初始化Braintree管理类
        braintreeManager = BraintreeManager(this, commonRepository, this)
    }

    // 调用BraintreeManager的方法触发支付界面
    fun loadDropIn() {
        braintreeManager.loadDropIn()
    }

    // 权限请求逻辑保留在Activity中
    private fun checkPermission(permission: String, requestCode: Int) {
        if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_DENIED) {
            ActivityCompat.requestPermissions(this, arrayOf(permission), requestCode)
        } else {
            Toast.makeText(this, "Permission already granted", Toast.LENGTH_SHORT).show()
        }
    }

    // DropInListener回调实现,可直接调用Manager的方法处理业务
    override fun onDropInSuccess(dropInResult: DropInResult) {
        Log.d("TAG2", "dropin success")
        val paymentMethodNonce = dropInResult.paymentMethodNonce?.string
        braintreeManager.collectDeviceData(paymentMethodNonce)
    }

    override fun onDropInFailure(error: Exception) {
        if (error is UserCanceledException) {
            Log.d("TAG2", "dropin user cancelled : ${error.message}")
        } else {
            Log.d("TAG2", "dropin failure : ${error.message}")
        }
    }
}

关键优化点

  • 解耦依赖:通过构造函数传递AppCompatActivity、CommonRepository和DropInListener,避免管理类直接继承Activity,降低耦合度。
  • 职责分离:Activity负责界面、权限请求和回调接收,BraintreeManager专注于Braintree SDK的初始化和业务逻辑处理。
  • 避免单例滥用:移除原代码中MainActivity.INSTANCE这种单例引用,改用实例传递,减少内存泄漏风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:46:14