简体   繁体   English

Android recycler查看和数据绑定

[英]Android recyclerView and data binding

I make an Android application in Kotlin, and i want to get some information from the webserver and put in a recycler view using data binding.我在 Kotlin 中创建了一个 Android 应用程序,我想从网络服务器获取一些信息并使用数据绑定放入回收站视图。 I use repository pattern, so each time i make a get request, i save the information in room database and get data from it with live data.我使用存储库模式,所以每次我发出获取请求时,我都会将信息保存在房间数据库中,并使用实时数据从中获取数据。 For some reason my ryclerview show nothing, and i get no errors.出于某种原因,我的 ryclerview 没有显示任何内容,并且我没有收到任何错误。 The request work and i get the data but the recyclerview not working.请求有效,我得到了数据,但 recyclerview 不起作用。 My ViewModel:我的视图模型:

class HomeViewModel(application: Application) : ViewModel() {
    private val availableTicketsRepo = AvailableTicketsRepository(getInstance(application))

    val tickets = availableTicketsRepo.availableTickets

    init {
        refreshDataFromRepository()
    }

    private fun refreshDataFromRepository() {
        viewModelScope.launch {
            try {
                availableTicketsRepo.refreshAvailableTickets()
            } catch (ex: Exception) {
                ex.message?.let { Resource.error(data = null, message = it) }
                Log.i("Home", "*** Eccezione: ${ex} ***")
            }
        }
    }

My fragment class (with adapter and viewholder):我的片段 class (带适配器和视图):

package com.example.ticketapp.ui.home

class HomeFragment : Fragment() {

    private val viewModel: HomeViewModel by lazy {
        val activity = requireNotNull(this.activity) {
            "You can only access the viewModel after onActivityCreated()"
        }
        ViewModelProvider(this, HomeViewModel.Factory(activity.application))
            .get(HomeViewModel::class.java)
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val binding = DataBindingUtil.inflate<FragmentHomeBinding>(
            inflater,
            R.layout.fragment_home,
            container,
            false
        )

        binding.lifecycleOwner = this
        binding.viewModel = viewModel

        binding.availableTicketsList.adapter = AvailableTicketsAdapter()


        return binding.root
    }
}

class AvailableTicketsAdapter() :
    ListAdapter<AvailableTicket, AvailableTicketsAdapter.AvailableTicketViewHolder>(DiffCallback) {

    class AvailableTicketViewHolder(private var binding: AvailableTicketItemsBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(tickets: AvailableTicket) {
            binding.ticket = tickets
            binding.executePendingBindings()
        }
    }

    companion object DiffCallback : DiffUtil.ItemCallback<AvailableTicket>() {
        override fun areItemsTheSame(oldItem: AvailableTicket, newItem: AvailableTicket): Boolean {
            return oldItem === newItem
        }

        override fun areContentsTheSame(
            oldItem: AvailableTicket,
            newItem: AvailableTicket
        ): Boolean {
            return oldItem.Id == newItem.Id
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AvailableTicketViewHolder {
        return AvailableTicketViewHolder(
            AvailableTicketItemsBinding.inflate(
                LayoutInflater.from(
                    parent.context
                )
            )
        )
    }


    override fun onBindViewHolder(holder: AvailableTicketViewHolder, position: Int) {
        val tickets = getItem(position)
        holder.bind(tickets)
    }
}

My repository:我的存储库:

class AvailableTicketsRepository(private val database: TicketDatabase) {
    val availableTickets: LiveData<List<AvailableTicket>> =
        Transformations.map(database.ticketDatabaseDao.getAvailableTickets()) {
            it.asDomainModel()
        }


    suspend fun refreshAvailableTickets() {
        withContext(Dispatchers.IO) {
            val tickets = RetrofitBuilder.apiService.getAvailableTickets()
            database.ticketDatabaseDao.insertAllAvailableTickets(tickets.map { it.asDataBaseModel() })
        }
    }
}

The xml for items in recylerview: recyclerview 中项目的 xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="android.view.View"/>
        <variable
            name="ticket"
            type="com.example.ticketapp.model.AvailableTicket" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:maxLength="50"
            android:text="@{ticket.title}"
            android:singleLine="true"
            android:textAlignment="center"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="Titolo di max 50 caratteri per non uscire dalla riga" />


        <TextView
            android:id="@+id/customerText"
            android:layout_width="160dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:textSize="14sp"
            android:text="@{ticket.customer}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/titleText"
            tools:text="ESEMPIO DI UN REFERENTE" />

        <TextView
            android:id="@+id/dateText"
            android:layout_width="80dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:textAlignment="textEnd"
            android:textSize="14sp"
            android:text="@{ticket.date_Time}"
            app:layout_constraintBaseline_toBaselineOf="@+id/customerText"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/titleText"
            tools:text="20/01/2021 10:00:00" />

        <ImageView
            android:id="@+id/warningImg"
            style="@style/iconImg"
            android:layout_marginTop="20dp"
            android:visibility="@{ticket.triangle ? View.VISIBLE : View.GONE}"
            android:foregroundGravity="center"
            app:layout_constraintEnd_toStartOf="@+id/dateText"
            app:layout_constraintStart_toEndOf="@+id/customerText"
            app:layout_constraintTop_toBottomOf="@+id/titleText"
            app:srcCompat="@drawable/ic_warning" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

XML of ryclerview: ryclerview的XML:

<androidx.recyclerview.widget.RecyclerView
           android:id="@+id/availableTicketsList"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:paddingStart="10dp"
           android:paddingEnd="10dp"
           app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/toolbar"
           tools:listitem="@layout/available_ticket_items" />

My Model class:我的 Model class:

@Parcelize
data class AvailableTicket (
   val Id: Int,
   val Title: String,
   val Description: String,
   val Date_Time: String,
   val Customer: String,
   val Field: String,
   val Category: String,
   val Color: String,
   val Author: String,
   val Triangle: Boolean,
   val MyPriority: String
): Parcelable

You should, notify adapter when data is modified, add a LiveData inside ViewModel and post it after availableTicketsRepo.refreshAvailableTickets() , then call submitList inside adapter once the data is received您应该在修改数据时通知适配器,在ViewModel中添加LiveData并将其发布在availableTicketsRepo.refreshAvailableTickets()之后,然后在收到数据后调用适配器内部的submitList

ViewModel视图模型

class HomeViewModel(application: Application) : ViewModel() {
    private val availableTicketsRepo = AvailableTicketsRepository(getInstance(application))
    val tickets = availableTicketsRepo.availableTickets

    init {
        refreshDataFromRepository()
    }

    private fun refreshDataFromRepository() {
        viewModelScope.launch {
            try {
                availableTicketsRepo.refreshAvailableTickets()
            } catch (ex: Exception) {
                ex.message?.let { Resource.error(data = null, message = it) }
                Log.i("Home", "*** Eccezione: ${ex} ***")
            }
        }
    }
}

Then in Fragment , submit list to adapter once fetched然后在Fragment中,将列表提交给适配器一旦获取

override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val binding = DataBindingUtil.inflate<FragmentHomeBinding>(
            inflater,
            R.layout.fragment_home,
            container,
            false
        )

        binding.lifecycleOwner = this
        binding.viewModel = viewModel

        binding.availableTicketsList.adapter = AvailableTicketsAdapter()

        viewModel.tickets.observe(this, Observer{
            (binding.availableTicketsList.adapter as? AvailableTicketsAdapter)?.submitList(it)
        })
        return binding.root
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM