Android如何通过回调将Adapter内的业务逻辑迁移至Activity类
Android OrderAdapter逻辑迁移到Activity的规范实现方案
核心思路是通过自定义回调接口解耦Adapter和Activity,Adapter仅负责列表数据渲染,业务逻辑、网络请求、UI操作全部收归Activity处理,符合单一职责开发规范。
第一步:定义回调接口
在OrderAdapter内部定义回调接口,用于将Adapter侧计算好的下单参数透传给Activity:
// 放在OrderAdapter类内部最上方 interface OnPlaceOrderListener { // 总金额变化时通知Activity更新按钮文案 fun onTotalChanged(newTotal: Int) // 下单时透传所有需要的参数 fun onPlaceOrder( totalAmount: Int, restaurantId: String, foodItemJsonArray: JSONArray ) }
第二步:改造OrderAdapter
移除构造参数中所有Activity侧的View引用(按钮、进度条、布局等),仅保留必要参数和回调接口,删除Adapter内的点击事件、网络请求、跨页面跳转逻辑:
class OrderAdapter( val context: Context, val userId: String, private val listener: OnPlaceOrderListener ) : RecyclerView.Adapter<OrderAdapter.OrderViewHolder>() { var total = 0 val foodJsonArr = JSONArray() var restaurantId: String = "" var list: List<Cart_Items> = CartData( context, Cart_Items(0, "", "", "", ""), "getall" ).execute().get() as List<Cart_Items> class OrderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var finalPrice:Int = 0 var name: TextView = itemView.findViewById(R.id.ord_item_item_name) var price: TextView = itemView.findViewById(R.id.ord_item_item_price) private var spinner: Spinner = itemView.findViewById(R.id.spinner) private val quantityArray = itemView.context.resources.getIntArray(R.array.quantity) init { val intArray = quantityArray.toTypedArray() val adapter = ArrayAdapter<Int>(itemView.context, android.R.layout.simple_spinner_item, intArray) spinner.adapter = adapter } fun bind(data: Cart_Items, onQuantityUpdate: (newPrice: Int) -> Unit) { name.text = data.itemName finalPrice = data.itemPrice.toInt() price.text = "₹ $finalPrice /-" spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onNothingSelected(parent: AdapterView<*>?) {} override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { val quantity = quantityArray[position] finalPrice = data.itemPrice.toInt() * quantity price.text = "₹ $finalPrice /-" onQuantityUpdate.invoke(finalPrice) } } } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.single_item, parent, false) return OrderViewHolder(view) } override fun getItemCount(): Int = list.size override fun onBindViewHolder(holder: OrderViewHolder, position: Int) { val data = list[position] if (position == 0) restaurantId = data.itemResId holder.bind(data) { newPrice -> recalculateTotal() listener.onTotalChanged(total) } val foodObj = JSONObject() foodObj.put("food_item_id", data.item_id) foodJsonArr.put(foodObj) total += data.itemPrice.toInt() } private fun recalculateTotal() { total = 0 // 可根据实际业务逻辑累加每个商品的选中价格 list.forEach { total += it.itemPrice.toInt() } } }
第三步:改造OrderPlaceActivity
Activity实现回调接口,所有网络请求、UI切换、页面跳转逻辑都放在Activity侧处理:
class OrderPlaceActivity : AppCompatActivity(), OrderAdapter.OnPlaceOrderListener { lateinit var recl_view: RecyclerView lateinit var place_order_button:Button lateinit var ord_res_name:TextView lateinit var prgs:RelativeLayout lateinit var order_placed:ConstraintLayout private lateinit var orderAdapter: OrderAdapter private var currentTotal = 0 private val userId by lazy { getSharedPreferences("details", Context.MODE_PRIVATE).getString("user_id","") ?: "" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_place_order) initView() initAdapter() initListener() } private fun initView() { recl_view = findViewById(R.id.ord_recl_view) ord_res_name = findViewById(R.id.ord_res_name) prgs = findViewById(R.id.ord_prgs) order_placed = findViewById(R.id.ord_placed) place_order_button = findViewById(R.id.ord_place_order) recl_view.layoutManager = LinearLayoutManager(this) } private fun initAdapter() { orderAdapter = OrderAdapter(this, userId, this) recl_view.adapter = orderAdapter // 初始化餐厅名称 if (orderAdapter.list.isNotEmpty()) { ord_res_name.text = "Ordering From ${orderAdapter.list[0].itemRes}" } currentTotal = orderAdapter.total updateOrderBtnText() } private fun initListener() { place_order_button.setOnClickListener { onPlaceOrder(currentTotal, orderAdapter.restaurantId, orderAdapter.foodJsonArr) } } override fun onTotalChanged(newTotal: Int) { currentTotal = newTotal updateOrderBtnText() } override fun onPlaceOrder(totalAmount: Int, restaurantId: String, foodItemJsonArray: JSONArray) { place_order_button.setBackgroundResource(R.color.grey) Handler(Looper.getMainLooper()).postDelayed({ if (!Connection().checkConnectivity(this)) { Toast.makeText(this,"请检查网络连接", Toast.LENGTH_SHORT).show() place_order_button.setBackgroundResource(R.color.colorPrimary) return@postDelayed } prgs.visibility = View.VISIBLE val requestQueue = Volley.newRequestQueue(this) val url = "http://13.235.250.119/v2/place_order/fetch_result/" try { val requestBody = JSONObject().apply { put("user_id", userId) put("restaurant_id", restaurantId) put("total_cost", totalAmount.toString()) put("food", foodItemJsonArray) } val jsonRequest = object : JsonObjectRequest( Method.POST, url, requestBody, { response -> prgs.visibility = View.GONE if (response.getJSONObject("data").getBoolean("success")) { showOrderSuccessView() } }, { prgs.visibility = View.GONE Toast.makeText(this,"请求失败,请稍后重试", Toast.LENGTH_SHORT).show() place_order_button.setBackgroundResource(R.color.colorPrimary) }) { override fun getHeaders(): MutableMap<String, String> { return hashMapOf( "Content-type" to "application/json", "token" to "c3acf1e14c21f9" ) } } requestQueue.add(jsonRequest) } catch (e: Exception) { prgs.visibility = View.GONE Toast.makeText(this,"发生错误,请稍后重试", Toast.LENGTH_SHORT).show() place_order_button.setBackgroundResource(R.color.colorPrimary) } }, 200) } private fun updateOrderBtnText() { place_order_button.text = "下单(总金额:$currentTotal)" } private fun showOrderSuccessView() { order_placed.visibility = View.VISIBLE val okBtn = order_placed.findViewById<Button>(R.id.ord_ok) okBtn.setOnClickListener { okBtn.setBackgroundResource(R.color.red) Handler(Looper.getMainLooper()).postDelayed({ val deleteSuccess = CartData(this, Cart_Items(0,"","","",""), "deleteall") .execute().get() as Boolean if (deleteSuccess) { order_placed.visibility = View.GONE okBtn.setBackgroundResource(R.color.grey) startActivity(Intent(this, MainActivity::class.java)) finish() } }, 200) } } }
规范说明
- Adapter仅负责列表项渲染,不持有Activity侧的View引用,避免内存泄漏
- 所有业务逻辑、UI操作、网络请求全部收归Activity处理,职责划分清晰
- 回调接口仅做参数透传,两层之间没有强耦合,后续修改逻辑不需要改动Adapter代码
- 修复了原代码中Spinner修改商品数量后总金额不同步的问题
内容的提问来源于stack exchange,提问作者yazhini
相关产品推荐
相关产品推荐

