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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 02:54:02