在InformationFragment中应向AdapterItem传递何种Context?
Android Fragment中实例化RecyclerView Adapter的Context传递问题
问题场景
在InformationFragment中通过Retrofit获取数据后,需要实例化AdapterItem,但不清楚该向其构造方法传递什么Context(无法使用baseContext),相关代码如下:
AdapterItem 原代码
class AdapterItem(val context: Context, val userList: List) : RecyclerView.Adapter<AdapterItem.ViewHolder>() { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var numeLista: TextView var caloriiLista: TextView init { numeLista = itemView.numeLista caloriiLista = itemView.caloriiLista } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { var itemView = LayoutInflater.from(context).inflate(R.layout.row_items, parent, false) return ViewHolder(itemView) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.numeLista.text = userList[position].foodItems.get(0).foodName holder.caloriiLista.text = userList[position].foodItems.get(0).calories.toString() } override fun getItemCount(): Int { return userList.size } }
InformationFragment 原代码
const val BASE_URL = "https://raw.githubusercontent.com/terrenjpeterson/caloriecounter/master/src/data/" class InformationFragment : Fragment() { private var binding: FragmentInformationBinding? = null private val sharedViewModel: SharedViewModel by activityViewModels() lateinit var adapterItem: AdapterItem lateinit var linearLayoutManager: LinearLayoutManager override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // 原代码存在空指针隐患:未初始化binding就操作recyclerview_lista recyclerview_lista.setHasFixedSize(true) linearLayoutManager = LinearLayoutManager(this.context) recyclerview_lista.layoutManager = linearLayoutManager getMyData() val fragmentBinding = FragmentInformationBinding.inflate(inflater, container, false) binding = fragmentBinding return fragmentBinding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding?.apply { viewModel = sharedViewModel informationFragment = this@InformationFragment lifecycleOwner = viewLifecycleOwner } } private fun getMyData() { val retrofitBuilder = Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .baseUrl(BASE_URL) .build() .create(ApiInterface::class.java) val retrofitData = retrofitBuilder.getData() retrofitData.enqueue(object : Callback<List<MyDataItem>?> { override fun onResponse( call: Call<List<MyDataItem>?>, response: Response<List<MyDataItem>?> ) { val responseBody = response.body()!! adapterItem = AdapterItem(, responseBody) // 此处Context参数缺失 adapterItem.notifyDataSetChanged() recyclerview_list.adapter = adapterItem } override fun onFailure(call: Call<List<MyDataItem>?>, t: Throwable) { Log.d("informationFragment", "onFailure: " + t.message) } }) } }
解决方案
方案1:优化Adapter,移除构造方法中的Context参数
onCreateViewHolder方法中的parent参数本身持有有效Context,完全不需要在Adapter构造中额外传递Context,这是更简洁的实现方式:
// 移除Context参数,同时明确泛型类型 class AdapterItem(val userList: List<MyDataItem>) : RecyclerView.Adapter<AdapterItem.ViewHolder>() { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { // 简化变量初始化 val numeLista: TextView = itemView.numeLista val caloriiLista: TextView = itemView.caloriiLista } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { // 使用parent.context获取LayoutInflater val itemView = LayoutInflater.from(parent.context) .inflate(R.layout.row_items, parent, false) return ViewHolder(itemView) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = userList[position] holder.numeLista.text = item.foodItems[0].foodName holder.caloriiLista.text = item.foodItems[0].calories.toString() } override fun getItemCount(): Int = userList.size }
此时Fragment中实例化Adapter时无需传递Context:
// 在onResponse回调中 response.body()?.let { dataList -> adapterItem = AdapterItem(dataList) binding?.recyclerview_lista?.adapter = adapterItem }
方案2:保留原Adapter结构,传递安全的Context
如果必须保留Adapter构造中的Context参数,可在Fragment中使用以下两种安全方式获取Context:
requireContext():Fragment附着在Activity上时返回非空Context,未附着时抛出异常,适合确定Fragment处于活跃状态的场景view.context:需确保view已初始化(例如在onViewCreated之后调用接口)
同时修复原Fragment中的空指针问题,修改后的关键代码:
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val fragmentBinding = FragmentInformationBinding.inflate(inflater, container, false) binding = fragmentBinding // 先初始化binding再操作RecyclerView binding?.recyclerview_lista?.apply { setHasFixedSize(true) layoutManager = LinearLayoutManager(context) } getMyData() return fragmentBinding.root } private fun getMyData() { // ... Retrofit初始化代码不变 retrofitData.enqueue(object : Callback<List<MyDataItem>?> { override fun onResponse( call: Call<List<MyDataItem>?>, response: Response<List<MyDataItem>?> ) { response.body()?.let { dataList -> // 使用requireContext()传递安全的Context adapterItem = AdapterItem(requireContext(), dataList) binding?.recyclerview_lista?.adapter = adapterItem // 刚设置Adapter时会自动刷新,无需调用notifyDataSetChanged } } // ... onFailure代码不变 }) }
额外注意事项
- 避免使用
this.context,它可能为空,优先选择requireContext()或view.context - Retrofit回调是异步的,可通过
viewLifecycleOwner.lifecycle.currentState判断Fragment是否活跃,防止内存泄漏 - 必须先初始化ViewBinding,再操作其中的控件,避免空指针异常
内容的提问来源于stack exchange,提问作者Vlad Duta
相关产品推荐
相关产品推荐

