Обновите поле в firestore с выбранным значением Spinner при нажатии кнопки

#kotlin #fragment #android-spinner

Вопрос:

Мое приложение выходит из строя, когда я нажимаю кнопку, чтобы обновить поле в значении firestore со счетчиком.

Название коллекции — orders

Имя документа динамическое, model.id используется для его получения.

Имя поля: order_status

Новое значение, которое необходимо обновить для поля order_status , должно быть взято из счетчика.

Код работает нормально, и поле обновляется, когда я жестко кодирую значение, но оно выходит из строя, когда я хочу использовать выбранное значение spinner

Ниже приведена ошибка в Logcat

  kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
        at com.trad.ui.adapters.OrderStatusListAdapter.access$getBinding$p(OrderStatusListAdapter.kt:32)
        at com.trad.ui.adapters.OrderStatusListAdapter$onBindViewHolder$1.onClick(OrderStatusListAdapter.kt:84)
        at android.view.View.performClick(View.java:8160)
        at android.widget.TextView.performClick(TextView.java:16222)
        at android.view.View.performClickInternal(View.java:8137)
        at android.view.View.access$3700(View.java:888)
        at android.view.View$PerformClick.run(View.java:30236)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8512)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
 

OrdersByStatusFragment.kt

 class OrdersByStatusFragment : BaseFragment() {

    private lateinit var binding: OrderStatusLayoutBinding

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
       
        return inflater.inflate(R.layout.fragment_orders_by_status, container, false)
    }

    override fun onResume() {
        super.onResume()

        getOrderStatusList()
    }

    private fun getOrderStatusList() {
       
        showProgressDialog(resources.getString(R.string.please_wait))

        FirestoreClass().getOrderStatusList(this@OrdersByStatusFragment)
    }

    fun successOrderStatusList(orderStatusList: ArrayList<OrderStatus>) {

        hideProgressDialog()

        if (orderStatusList.size > 0) {

            rv_order_by_status.visibility = View.VISIBLE
            tv_no_orders_by_status_found.visibility = View.GONE

            rv_order_by_status.layoutManager = LinearLayoutManager(activity)
            rv_order_by_status.setHasFixedSize(true)

            val orderStatusListAdapter =
                OrderStatusListAdapter(requireActivity(), orderStatusList)

            rv_order_by_status.adapter = orderStatusListAdapter

        } else {

            rv_order_by_status.visibility = View.GONE
            tv_no_orders_by_status_found.visibility = View.VISIBLE
        }
    }

    fun successNewOrderStatus() {

        Toast.makeText(requireContext(), "Success", Toast.LENGTH_SHORT).show()

    }
}
 

OrderStatusListAdapter.kt

 open class OrderStatusListAdapter(
    private val context: Context,
    private var list: ArrayList<OrderStatus>,

    ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
  
    private lateinit var binding: OrderStatusLayoutBinding

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

        return MyViewHolder(OrderStatusLayoutBinding.inflate(LayoutInflater.from(parent.context), parent,false))
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val model = list[position]

        if (holder is MyViewHolder) {

            GlideLoader(context).loadProductPicture(
                model.image,
                holder.itemView.iv_order_status_item_image
            )

            val dateFormat = "dd MMM yyyy HH:mm"
           
            val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())

            val calendar: Calendar = Calendar.getInstance()
            calendar.timeInMillis = model.order_datetime

            val orderDateTime = formatter.format(calendar.time)
            holder.itemView.tv_order_status_order_date.text = orderDateTime

            holder.itemView.tv_order_status_item_name.text = model.items[0].title
            holder.itemView.tv_order_status_item_price.text = "${model.total_amount}"

            holder.itemView.tv_order_status.text = model.order_status
            holder.itemView.tv_order_status_order_id.text = model.id

            holder.itemView.btn_order_status_change_status.setOnClickListener {

                binding.spnOrderChangeStatus.onItemSelectedListener =
                    object : AdapterView.OnItemSelectedListener {
                        override fun onItemSelected(
                            parent: AdapterView<*>?,
                            view: View?,
                            position: Int,
                            id: Long
                        ) {
                            Toast.makeText(
                                context,
                                "Selected value is ${
                                    parent?.getItemAtPosition(position).toString()
                                }",
                                Toast.LENGTH_SHORT
                            ).show()

                            val newstat = parent?.getItemAtPosition(position).toString()
                            FirestoreClass().updateOrderStatus(model.id, newstat)

                        }

                        override fun onNothingSelected(parent: AdapterView<*>?) {

                        }
                    }

           }

            holder.itemView.ib_order_status_delete_product.visibility = View.GONE

            holder.itemView.setOnClickListener {
                val intent = Intent(context, SoldProductDetailsActivity::class.java)
                intent.putExtra(Constants.EXTRA_SOLD_PRODUCT_DETAILS, model)
                context.startActivity(intent)
            }


        }

    }

    override fun getItemCount(): Int {
        return list.size
    }

    inner class MyViewHolder(private val binding : OrderStatusLayoutBinding) : RecyclerView.ViewHolder(binding.root)
}
 

FirestoreClass.kt

 fun updateOrderStatus(
    orderID: String,
    newOrderStatus: String
) {
    mFireStore.collection(Constants.ORDERS)
        .document(orderID)
        .update("order_status", newOrderStatus)
        .addOnSuccessListener {


        }
        .addOnFailureListener {
        }
}
 

Редактировать


Ниже приведена новая ошибка.

 2021-06-09 01:24:17.550 2253-2253/com.tradaxis E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.tradaxis, PID: 2253
    java.lang.NullPointerException: rv_order_by_status must not be null
        at com.tradaxis.ui.fragments.OrdersByStatusFragment.successOrderStatusList(OrdersByStatusFragment.kt:76)
        at com.tradaxis.firestore.FirestoreClass$getOrderStatusList$1.onSuccess(FirestoreClass.kt:935)
        at com.tradaxis.firestore.FirestoreClass$getOrderStatusList$1.onSuccess(FirestoreClass.kt:22)
        at com.google.android.gms.tasks.zzn.run(Unknown Source:4)
        at android.os.Handler.handleCallback(Handler.java:938)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:246)
        at android.app.ActivityThread.main(ActivityThread.java:8512)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
 

rv_order_by_status.visibility = View.VISIBLE в «fun successOrderStatusList(список заказов: ArrayList)» находится код в OrdersByStatusFragment.kt:76

fragment.successOrderStatusList(list) в FirestoreClass.kt — это код в FirestoreClass.kt:935

class FirestoreClass { это код в FirestoreClass.kt:22

ПРИМЕЧАНИЕ: До внесения этих изменений в этих строках кода не было такой ошибки.

Комментарии:

1. Можете ли вы запустить приложение, скопировать и вставить полученную ошибку (отредактируйте ее в сообщении)?

2. Я обновил весь свой вопрос с исправленным кодом и ошибками, которые у меня есть.

Ответ №1:

В вашем OrderStatusFragment onCreateView вы не устанавливаете привязку. Тебе нужно сделать что-то вроде этого

  private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    val view = binding.root
    return view
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
}
 

Вместо привязки результата к файлу вы бы использовали свой фрагмент orderstatuslayout. Это не связано с firebase, но это должно исправить сбой, который у вас сейчас происходит.

Подробнее читайте: https://developer.android.com/topic/libraries/view-binding

Не забудьте ondestroy, чтобы избежать утечек памяти.