如何在伴生对象中定义带OnClickListener的Adapter并解决this报错?
你现在的问题核心有两个:
- 伴生对象里的
this指的是Companion静态内部类的实例,不是MainActivity的实例,而Adapter大概率需要Context或者Activity上下文,所以传这个this肯定报错。 - 用伴生对象存列表、Adapter这种和UI绑定的对象,很容易造成内存泄漏——因为静态变量的生命周期和App一致,MainActivity销毁后,这些变量还持有Activity相关引用,内存没法释放。
正确实现方式
方式1:用Activity Result API回传数据(最常用)
从其他Activity收集完数据后,通过Intent把数据带回来,MainActivity接收后更新RecyclerView:
- 首先在MainActivity里注册Activity Result回调:
// MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: Adapter private val recyclerViewItems = ArrayList<Itemclass>() // 注册回调,接收其他Activity返回的数据 private val getInputData = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == RESULT_OK) { val data = result.data ?: return@registerForActivityResult // 取出返回的名称和列表 val name = data.getStringExtra("KEY_NAME") ?: "" val questionList = data.getSerializableExtra("KEY_QUESTION_LIST") as? ArrayList<QuestionItemClass> ?: arrayListOf() // 封装成Item并添加到列表,更新Adapter val newItem = Itemclass(name, questionList) recyclerViewItems.add(newItem) adapter.notifyItemInserted(recyclerViewItems.size - 1) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化RecyclerView和Adapter recyclerView = findViewById(R.id.recyclerView) adapter = Adapter(recyclerViewItems, this) // 这里的this是MainActivity实例,没问题 recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(this) // 跳转到其他Activity的按钮点击事件 findViewById<Button>(R.id.btn_go_other).setOnClickListener { val intent = Intent(this, OtherActivity::class.java) getInputData.launch(intent) } } }
- 在其他Activity里,收集完数据后通过Intent返回:
// OtherActivity.kt class OtherActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_other) // 假设收集完数据后,点击确认按钮返回 findViewById<Button>(R.id.btn_confirm).setOnClickListener { val inputName = "用户输入的名称" // 替换成实际获取的名称 val inputList = arrayListOf<QuestionItemClass>() // 替换成实际获取的列表 val resultIntent = Intent() resultIntent.putExtra("KEY_NAME", inputName) // 注意:QuestionItemClass需要实现Serializable或者Parcelable接口 resultIntent.putExtra("KEY_QUESTION_LIST", inputList) setResult(RESULT_OK, resultIntent) finish() } } }
注意:
QuestionItemClass需要实现Serializable或者Parcelable接口,这样才能通过Intent传递。
方式2:用ViewModel共享数据(适合复杂场景)
如果你的页面逻辑比较复杂,或者需要在多个组件间共享数据,可以用ViewModel:
- 创建共享的ViewModel:
// SharedViewModel.kt class SharedViewModel : ViewModel() { val itemList = MutableLiveData<ArrayList<Itemclass>>() init { itemList.value = arrayListOf() } fun addItem(name: String, list: ArrayList<QuestionItemClass>) { val currentList = itemList.value ?: arrayListOf() currentList.add(Itemclass(name, list)) itemList.postValue(currentList) } }
- MainActivity里观察ViewModel的数据变化:
// MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: Adapter private lateinit var viewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取ViewModel实例 viewModel = ViewModelProvider(this)[SharedViewModel::class.java] // 初始化RecyclerView recyclerView = findViewById(R.id.recyclerView) adapter = Adapter(arrayListOf(), this) recyclerView.adapter = adapter recyclerView.layoutManager = LinearLayoutManager(this) // 观察列表变化,自动更新RecyclerView viewModel.itemList.observe(this) { newList -> adapter.updateList(newList) adapter.notifyDataSetChanged() } // 跳转到其他Activity findViewById<Button>(R.id.btn_go_other).setOnClickListener { val intent = Intent(this, OtherActivity::class.java) startActivity(intent) } } }
- 其他Activity里获取ViewModel并添加数据:
// OtherActivity.kt class OtherActivity : AppCompatActivity() { private lateinit var viewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_other) // 获取和MainActivity共享的ViewModel viewModel = ViewModelProvider(this@OtherActivity)[SharedViewModel::class.java] findViewById<Button>(R.id.btn_confirm).setOnClickListener { val inputName = "用户输入的名称" val inputList = arrayListOf<QuestionItemClass>() viewModel.addItem(inputName, inputList) finish() } } }
为什么原来的伴生对象方案不行?
- 伴生对象是静态成员,它的
this指向的是MainActivity.Companion这个静态类实例,不是MainActivity的上下文,所以Adapter接收的Context是错的,导致报错。 - 静态变量持有Adapter、列表这些对象,会让MainActivity即使销毁后也无法被GC回收,造成内存泄漏,严重影响App性能。
内容的提问来源于stack exchange,提问作者Mehmet Eren Erol
相关产品推荐
相关产品推荐

