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

Android Kotlin:onResponse初始化enrollBookAdapter仍报错的解决方法

问题

运行时出现如下报错:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.clone.practice/com.clone.practice.EnrollBookActivity}: kotlin.UninitializedPropertyAccessException: lateinit property enrollBookAdapter has not been initialized

原本预期在网络请求onResponse回调中执行response.body()?.let {}时,enrollBookAdapter会完成初始化,但实际未成功。请问哪里操作有误?该如何使用Books数据正确初始化bookList?

相关代码:

class EnrollBookActivity : AppCompatActivity() {

    private lateinit var binding: ActivityEnrollBookBinding
    private lateinit var bookService: BookService
    private lateinit var bookList:MutableList<Book>
    private lateinit var enrollBookAdapter: EnrollBookAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityEnrollBookBinding.inflate(layoutInflater)

        setContentView(binding.root)


        initBookService()
        bookServiceLoadBestSellers()


        binding.selfBtn.setOnClickListener{
            startActivity(Intent(this,SelfWriteActivity::class.java))
        }
        enrollBookAdapter.setOnBookClickListener(object:EnrollBookAdapter.OnBookClickListener{
            override fun onBookClick(position: Int, book: Book) {
                val intent = Intent(this@EnrollBookActivity,TalerMain::class.java)
                intent.putExtra("title",enrollBookAdapter.bookList[position].title)
                intent.putExtra("url",enrollBookAdapter.bookList[position].title)
                
                startActivity(intent)
            }

        })
    }
    private fun initBookRecyclerView(bookList: MutableList<Book>) {
        enrollBookAdapter = EnrollBookAdapter(bookList)
        enrollBookAdapter.setOnBookClickListener(object:EnrollBookAdapter.OnBookClickListener{
            override fun onBookClick(position: Int, book: Book) {
                val intent = Intent(this@EnrollBookActivity,TalerMain::class.java)
                intent.putExtra("title",enrollBookAdapter.bookList[position].title)
                intent.putExtra("url",enrollBookAdapter.bookList[position].title)
                startActivity(intent)
            }

        })
        binding.bookRv.layoutManager = GridLayoutManager(this,2)
        binding.bookRv.adapter = EnrollBookAdapter(bookList)
        binding.bookRv.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
    }
    private fun bookServiceLoadBestSellers() {
        bookService.getBestSellerBooks(getString(R.string.interparkAPIKey))
            .enqueue(object : Callback<BestSellerDto> {
                
                override fun onResponse(
                    call: Call<BestSellerDto>,
                    response: Response<BestSellerDto>
                ) {
                    
                    if (response.isSuccessful.not()) {
                        Log.e(M_TAG, "NOT!! SUCCESS")
                        return
                    }

                    
                    response.body()?.let {
                        Log.d(M_TAG, it.toString())

                        it.books.forEach { book ->
                            Log.d(M_TAG, book.toString())
                        }
                        
                        //enrollBookAdapter = EnrollBookAdapter(it.books as MutableList<Book>)
                        initBookRecyclerView(it.books as MutableList<Book>)
                        //setRecyclerView(it.books)
                    }
                }

                override fun onFailure(call: Call<BestSellerDto>, t: Throwable) {
                    Log.e(M_TAG, t.toString())
                }
            })
    }
}
问题分析

报错核心原因:onCreate中直接调用enrollBookAdapter.setOnBookClickListener时,enrollBookAdapter还未初始化。

网络请求是异步操作,bookServiceLoadBestSellers()调用后不会立刻执行onResponse回调,而onCreate会继续向下执行,此时enrollBookAdapter作为lateinit变量仍未被赋值,直接调用其方法必然抛出初始化异常。

此外还有两处额外问题:

  1. initBookRecyclerView中,先初始化了全局的enrollBookAdapter,但给RecyclerView设置的却是新创建的EnrollBookAdapter(bookList),导致全局变量和RecyclerView绑定的适配器不是同一个对象。
  2. 全局bookList变量从未被赋值,一直处于未初始化状态。
解决方案

1. 调整适配器初始化与监听设置时机

把设置点击监听的逻辑移到initBookRecyclerView方法中,确保在适配器初始化完成后再绑定监听。

2. 统一RecyclerView的适配器实例

在initBookRecyclerView中,给RecyclerView设置适配器时直接使用已初始化的enrollBookAdapter,避免创建重复实例。

3. 正确初始化全局bookList

在onResponse回调中通过initBookRecyclerView给全局bookList赋值。

修改后的完整代码:

class EnrollBookActivity : AppCompatActivity() {

    private lateinit var binding: ActivityEnrollBookBinding
    private lateinit var bookService: BookService
    private lateinit var bookList: MutableList<Book>
    private lateinit var enrollBookAdapter: EnrollBookAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityEnrollBookBinding.inflate(layoutInflater)
        setContentView(binding.root)

        initBookService()
        bookServiceLoadBestSellers()

        binding.selfBtn.setOnClickListener{
            startActivity(Intent(this,SelfWriteActivity::class.java))
        }
        // 移除此处未初始化的适配器监听设置
    }

    private fun initBookRecyclerView(books: MutableList<Book>) {
        // 初始化全局bookList
        bookList = books
        // 初始化适配器
        enrollBookAdapter = EnrollBookAdapter(bookList)
        // 设置点击监听
        enrollBookAdapter.setOnBookClickListener(object: EnrollBookAdapter.OnBookClickListener{
            override fun onBookClick(position: Int, book: Book) {
                val intent = Intent(this@EnrollBookActivity, TalerMain::class.java)
                intent.putExtra("title", book.title)
                intent.putExtra("url", book.url) // 修正原代码中url传title的错误
                startActivity(intent)
            }
        })
        // 设置RecyclerView参数
        binding.bookRv.layoutManager = GridLayoutManager(this, 2)
        binding.bookRv.adapter = enrollBookAdapter // 使用已初始化的适配器实例
        binding.bookRv.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
    }

    private fun bookServiceLoadBestSellers() {
        bookService.getBestSellerBooks(getString(R.string.interparkAPIKey))
            .enqueue(object : Callback<BestSellerDto> {
                override fun onResponse(
                    call: Call<BestSellerDto>,
                    response: Response<BestSellerDto>
                ) {
                    if (!response.isSuccessful) {
                        Log.e(M_TAG, "请求失败")
                        return
                    }

                    response.body()?.let { dto ->
                        Log.d(M_TAG, dto.toString())
                        dto.books.forEach { book ->
                            Log.d(M_TAG, book.toString())
                        }
                        // 安全转换为MutableList并初始化RecyclerView
                        initBookRecyclerView(dto.books.toMutableList())
                    }
                }

                override fun onFailure(call: Call<BestSellerDto>, t: Throwable) {
                    Log.e(M_TAG, t.toString())
                }
            })
    }
}

额外优化说明

  • 修正原代码中点击监听里把book.title作为url传递的错误。
  • 用toMutableList()替代强制类型转换as MutableList,避免不可变List转换时的异常。
  • 点击监听中直接使用回调参数的book对象,无需从适配器列表中重复获取,代码更简洁安全。

内容的提问来源于stack exchange,提问作者Joon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 03:50:17