#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, чтобы избежать утечек памяти.