Fragment 中的 RecyclerView 未填充

RecyclerView in Fragment not populating

所以我已经为此苦苦挣扎了好几天,我需要一些帮助。我已经使这段代码在 activity 中工作,但后来我将它移到一个它不起作用的片段中。两者其他都一样。

将调试器与工作 Activity 一起使用,行

apiService = retrofit.create<HomeJsonApiService>(HomeJsonApiService::class.java)

转到 getItemCount()。但是在片段中它直接转到片段中的 onCreateView。我在下面附上了我的代码。先谢谢您的帮助!并且要温柔。我对此还是个新手:)

首先是我的片段:

class TabHomeActivity : Fragment() {

    val itemList = ArrayList<HomeCards>()
    lateinit var adapter: HomeCardsAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)
        adapter = HomeCardsAdapter()
        var rv = binding.rvHomeCards
        rv.adapter = adapter
        loadData()
    }

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

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    private fun loadData() {
        ApiManager.getInstance().service.listHeroes()
            .enqueue(object : Callback<ResponseData<List<HomeCards>>> {

                override fun onResponse(
                    call: Call<ResponseData<List<HomeCards>>>,
                    response: Response<ResponseData<List<HomeCards>>>
                ) {
                    val listData: List<HomeCards> = response.body()!!.data

                    // updating data from network to adapter
                    itemList.clear()
                    itemList.addAll(listData)
                    adapter.updateData(itemList)
                    adapter.notifyDataSetChanged()
                }

                override fun onFailure(call: Call<ResponseData<List<HomeCards>>>, t: Throwable) {
                }

            })
    }

}

HTTP 请求:

data class ResponseData<T> (
    val code: Int,
    val data: T
)
interface HomeJsonApiService {
    @GET("marvel-heroes.asp?h=2")
    fun listHeroes(): retrofit2.Call<ResponseData<List<HomeCards>>>
}

class ApiManager {

    private var apiService: HomeJsonApiService? = null

    init {
        createService()
    }

    val service: HomeJsonApiService get() = apiService!!

    private fun createService() {
        val loggingInterceptor =
            HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
                override fun log(message: String) {
                    Log.i("Retrofit", message)
                }
            })

        loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

        val client = OkHttpClient.Builder()
            .readTimeout(30, TimeUnit.SECONDS)
            .connectTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .build()

        val retrofit: Retrofit = Retrofit.Builder()
            .client(client)
            .baseUrl("https://www.mywebsite.com/jsonfolder/JSON/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        apiService = retrofit.create(HomeJsonApiService::class.java)
    }

    companion object {

        private var instance: ApiManager? = null

        fun getInstance(): ApiManager {
            return instance ?: synchronized(this) {
                ApiManager().also { instance = it }
            }
        }
    }

}

我的适配器:

class HomeCardsAdapter() : RecyclerView.Adapter<HomeCardsAdapter.ViewHolder>() {

    private lateinit var itemList: List<HomeCards>
    lateinit var context: Context

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        context = parent.context
        val view = LayoutInflater.from(context).inflate(R.layout.cards_home, parent, false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int {
        return if (::itemList.isInitialized) itemList.size else 0
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind()
    }

    fun updateData(list: List<HomeCards>) {
        itemList = list;
        notifyDataSetChanged()
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        //var binding = ActivityMainBinding(layoutInflater(inf))

        fun bind() {
            val item = itemList.get(adapterPosition)

            ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.name
            ViewHolder(itemView).itemView.findViewById<TextView>(R.id.cardHomeTitle).text = item.superheroName

            Glide.with(context)
                .load(item.photo)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .circleCrop()
                .into(ViewHolder(itemView).itemView.findViewById<ImageView>(R.id.cardHomeIcon))
        }
    }
}

class HomeCards {
    @SerializedName("superhero_name")
    var superheroName: String = ""
    var name: String = ""
    var photo: String = ""
}

如果 onResponse() 被调用并提供响应,验证代码更新 UI 是 运行 在 main/ui 线程上。使用网络(其他线程)时的常见问题来源。

activity?.runOnUiThread {
   itemList.clear()
   itemList.addAll(listData)
   adapter.updateData(itemList)
   adapter.notifyDataSetChanged()
}

主要问题是:

var binding = FragmentTabHomeActivityBinding.inflate(layoutInflater)

那是在 onCreate 里面,但是 onCreateView 正在返回另一个视图 inflater.inflate(R.layout.cards_home, container, false)

因此,您正在将适配器应用于绑定上的回收器,但屏幕上的视图从布局中膨胀。改成这样:

private lateinit var binding: FragmentTabHomeActivityBinding

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

并将代码从 onCreate 移至 onViewCreated,但请确保使用 lateinit binding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        adapter = HomeCardsAdapter()
        var rv = binding.rvHomeCards
        rv.adapter = adapter
        loadData()
    }

之后您的适配器出现问题:private lateinit var itemList: List<HomeCards> 非常具体 List<HomeCards>。方法 notifyDataSetChanged 不会通过更改或更新数据结构的引用来工作,而是在修改集合时工作。改成这样:

private val list = mutableListOf<HomeCards>()


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

    fun updateData(list: List<HomeCards>) {
        this.itemList.clear()
        this.itemList.addAll(list)
        notifyDataSetChanged()
    }