Kotlin Android+Capacitor跨类更新Presentation视图的最佳设计模式
解决Capacitor插件更新Android副屏Presentation视图的合理方案
1. 让Activity接管Presentation的生命周期
Presentation实例得交给主Activity来创建和管理,不能让Capacitor插件直接持有——毕竟Presentation依赖显示设备和宿主Context,插件本身是无状态的,硬拿Context属于反模式,还容易搞出内存泄漏。
先在你的主Activity里加副屏监听和Presentation管理逻辑:
class MainActivity : BridgeActivity() { private var secondaryScreenPresentation: SecondaryScreenPresentation? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupSecondaryScreenListener() } private fun setupSecondaryScreenListener() { val displayManager = getSystemService(DISPLAY_SERVICE) as DisplayManager displayManager.registerDisplayListener(object : DisplayManager.DisplayListener { override fun onDisplayAdded(displayId: Int) { val display = displayManager.getDisplay(displayId) // 排除主屏幕,只处理副屏 if (display != null && display.displayId != Display.DEFAULT_DISPLAY) { secondaryScreenPresentation = SecondaryScreenPresentation(this@MainActivity, display) secondaryScreenPresentation?.show() } } override fun onDisplayRemoved(displayId: Int) { secondaryScreenPresentation?.dismiss() secondaryScreenPresentation = null } override fun onDisplayChanged(displayId: Int) {} }, Handler(Looper.getMainLooper())) } // 对外提供更新副屏数据的方法 fun updateSecondaryScreenCart(transaction: Transaction) { secondaryScreenPresentation?.updateCartItems(transaction.items) } }
然后写Presentation类,内部处理RecyclerView和Adapter:
class SecondaryScreenPresentation(context: Context, display: Display) : Presentation(context, display) { private lateinit var cartItemAdapter: CartItemAdapter private val cartItems = mutableListOf<CartItem>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.secondary_screen_layout) // 这个布局里要包含RecyclerView val recyclerView = findViewById<RecyclerView>(R.id.cart_recycler_view) recyclerView.layoutManager = LinearLayoutManager(context) cartItemAdapter = CartItemAdapter(context, cartItems) recyclerView.adapter = cartItemAdapter } // 更新购物车数据并刷新Adapter fun updateCartItems(newItems: List<CartItem>) { cartItems.clear() cartItems.addAll(newItems) cartItemAdapter.notifyDataSetChanged() } }
2. 在Capacitor插件中安全调用Activity的更新方法
插件里可以通过getBridge().getActivity()拿到当前的主Activity,强转后直接调用更新方法就行,注意必须在主线程操作UI:
@PluginMethod fun transactionChange(call: PluginCall) { val itemsJson = call.getString("items") ?: run { call.reject("缺少items参数") return } try { val transaction = Json.decodeFromString<Transaction>(itemsJson) val mainActivity = getBridge().getActivity() as? MainActivity ?: run { call.reject("无法获取MainActivity实例") return } // 切到主线程更新UI Handler(Looper.getMainLooper()).post { mainActivity.updateSecondaryScreenCart(transaction) val ret = JSObject() ret.put("success", true) call.resolve(ret) } } catch (e: Exception) { call.reject("解析交易数据失败: ${e.message}") } }
3. 进阶优化:用LiveData实现解耦更新
如果想让组件之间更解耦,不用直接调用方法,可以用LiveData做数据驱动:
在MainActivity里加一个MutableLiveData:
class MainActivity : BridgeActivity() { private val transactionLiveData = MutableLiveData<Transaction?>() private var secondaryScreenPresentation: SecondaryScreenPresentation? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupSecondaryScreenListener() observeTransactionUpdates() } private fun observeTransactionUpdates() { transactionLiveData.observe(this) { transaction -> transaction?.let { secondaryScreenPresentation?.updateCartItems(it.items) } } } fun updateSecondaryScreenCart(transaction: Transaction) { transactionLiveData.postValue(transaction) } // 副屏监听代码不变... }
然后Presentation里直接观察这个LiveData,不用依赖Activity的方法调用:
class SecondaryScreenPresentation(context: Context, display: Display) : Presentation(context, display) { private lateinit var cartItemAdapter: CartItemAdapter private val cartItems = mutableListOf<CartItem>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.secondary_screen_layout) val recyclerView = findViewById<RecyclerView>(R.id.cart_recycler_view) recyclerView.layoutManager = LinearLayoutManager(context) cartItemAdapter = CartItemAdapter(context, cartItems) recyclerView.adapter = cartItemAdapter // 观察MainActivity的LiveData,自动更新数据 (context as? MainActivity)?.transactionLiveData?.observe(this) { transaction -> transaction?.let { updateCartItems(it.items) } } } // updateCartItems方法不变... }
为什么不能用伴生方法?
伴生方法(静态方法)持有Context会导致内存泄漏——静态引用会一直攥着Context实例,哪怕Activity已经销毁了。让Activity持有Presentation实例,跟着Activity的生命周期创建/销毁Presentation,既符合Android的组件规范,又能避免内存泄漏问题。
内容的提问来源于stack exchange,提问作者Zach Wright
相关产品推荐
相关产品推荐

