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
相关产品推荐
相关产品推荐

