如何在Adapter中正确的使用Context
1. 前言
最近我在项目中,发现一个同事写 RecyclerView.Adapter 的时候都习惯定义一个全局的私有 mContext
,然后在onCreateViewHolder(parent: ViewGroup, viewType: Int)
方法中进行赋值操作 mContext = parent.context
。
如下:
class MyAdapter(private val dataList: List<MyData>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {private lateinit var mContext: Contextoverride fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {//在这里进行context的赋值mContext = parent.contextval view = LayoutInflater.from(parent.context).inflate(R.layout.rcy_item_view, parent, false)return MyViewHolder(view)}override fun getItemCount(): Int {}override fun onBindViewHolder(holder: MyViewHolder, position: Int) {}
}
WT,还可以这么操作!!第一次见到这样的写法,有点意思,由此有了这一篇文章。
2. 获取到 Context 的四种方式
很多时候我们需要在 RecyclerView.Adapter 中使用到 context,比如:利用 Glide 来加载网络图片的时候。
这时,我们该如何拿到 context 给 Glide 呢?
2.1 通过 Adapter 构造函数传入 Context
这是我之前最常用的一种方式,通过 Adapter 构造函数将当前Activity Context传进来,如下:
class MyAdapter(private val context: Context,private val dataList: List<MyData>
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {class MyViewHolder(val binding: RcyItemViewBinding) :RecyclerView.ViewHolder(binding.root) {}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {val binding = RcyItemViewBinding.inflate(LayoutInflater.from(parent.context),parent,false)return MyViewHolder(binding)}override fun getItemCount(): Int = dataList.sizeoverride fun onBindViewHolder(holder: MyViewHolder, position: Int) {val data = dataList[position]holder.binding.apply {Glide.with(context).load(data.imageUrl).into(holder.binding.imageIv)holder.binding.contentTv.text = data.content}}
}
2.2 通过 Parent.context 获取
这个也是文章开头中提到的我的同事的一种写法,如下:
class MyAdapter(private val dataList: List<MyData>) :RecyclerView.Adapter<MyAdapter.MyViewHolder>() {private lateinit var mContext: Contextclass MyViewHolder(val binding: RcyItemViewBinding) :RecyclerView.ViewHolder(binding.root) {}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {mContext = parent.contextval binding = RcyItemViewBinding.inflate(LayoutInflater.from(parent.context),parent,false)return MyViewHolder(binding)}override fun getItemCount(): Int = dataList.sizeoverride fun onBindViewHolder(holder: MyViewHolder, position: Int) {val data = dataList[position]holder.binding.apply {Glide.with(mContext).load(data.imageUrl).into(holder.binding.imageIv)holder.binding.contentTv.text = data.content}}
}
2.3 通过 onAttachedToRecyclerView() 方法获取
对于2.2 的方法,通过 parent.context 对 mContext 进行赋值,有人说,不可以这么操作!这样会导致内存泄露!!(留个疑问?你觉得2.2方法这样操作会导致内存泄漏吗?
)
所以你需要覆写 onAttachedToRecyclerView(recyclerView: RecyclerView)
方法,在这里对 mContext 进行赋值。如下:
class MyAdapter(private val dataList: List<MyData>) :RecyclerView.Adapter<MyAdapter.MyViewHolder>() {private lateinit var mContext: Contextoverride fun onAttachedToRecyclerView(recyclerView: RecyclerView) {super.onAttachedToRecyclerView(recyclerView)mContext = recyclerView.context}class MyViewHolder(val binding: RcyItemViewBinding) :RecyclerView.ViewHolder(binding.root) {}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {val binding = RcyItemViewBinding.inflate(LayoutInflater.from(parent.context),parent,false)return MyViewHolder(binding)}override fun getItemCount(): Int = dataList.sizeoverride fun onBindViewHolder(holder: MyViewHolder, position: Int) {val data = dataList[position]holder.binding.apply {Glide.with(mContext).load(data.imageUrl).into(holder.binding.imageIv)holder.binding.contentTv.text = data.content}}
}
2.4 通过 ImageView 获取 context
当当就我们举的这个例子,因为我们需要用到 Glide 来展示网络图片,所以我们需要传递 Context 给 Glide,其实我们可以直接通过 ImageView 来拿到 context,然后传给 Glide,如下:
class MyAdapter(private val dataList: List<MyData>) :RecyclerView.Adapter<MyAdapter.MyViewHolder>() {class MyViewHolder(val binding: RcyItemViewBinding) :RecyclerView.ViewHolder(binding.root) {}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {val binding = RcyItemViewBinding.inflate(LayoutInflater.from(parent.context),parent,false)return MyViewHolder(binding)}override fun getItemCount(): Int = dataList.sizeoverride fun onBindViewHolder(holder: MyViewHolder, position: Int) {val data = dataList[position]holder.binding.apply {Glide.with(imageIv.context).load(data.imageUrl).into(holder.binding.imageIv)holder.binding.contentTv.text = data.content}}
}
3. 问题的本质
上面介绍了四种方法来获取 Context,想必大家都想弄清楚上面几种方法有什么区别吧,那我们就打印他们获取到的 context 出来瞧瞧看吧,如下:
class MainActivity : AppCompatActivity() {private lateinit var binding: ActivityMainBinding···override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)Log.e("jctest", "onCreate: this::class.java = ${this::class.java}")Log.e("jctest", "onCreate: binding.recyclerView.context::class.java = ${binding.recyclerView.context::class.java}")val adapter = MyAdapter(listData)binding.recyclerView.adapter = adapter}class MyAdapter(private val dataList: List<MyData>) :RecyclerView.Adapter<MyAdapter.MyViewHolder>() {class MyViewHolder(val binding: RcyItemViewBinding) :RecyclerView.ViewHolder(binding.root) {}override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {Log.e("jctest", "onCreateViewHolder: parent::class.java = ${parent::class.java}")Log.e("jctest", "onCreateViewHolder: parent.context::class.java = ${parent.context::class.java}")val binding = RcyItemViewBinding.inflate(LayoutInflater.from(parent.context),parent,false)return MyViewHolder(binding)}override fun getItemCount(): Int = dataList.sizeoverride fun onBindViewHolder(holder: MyViewHolder, position: Int) {val data = dataList[position]holder.binding.apply {Log.e("jctest", "onBindViewHolder: imageIv.context::class.java = ${imageIv.context::class.java}")Glide.with(imageIv.context).load(data.imageUrl).into(holder.binding.imageIv)holder.binding.contentTv.text = data.content}}override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {super.onAttachedToRecyclerView(recyclerView)Log.e("jctest", "onAttachedToRecyclerView: recyclerView.context::class.java = ${recyclerView.context::class.java}")}}}
打印出来的 Log 如下:
E/jctest: onCreate: this::class.java = class com.jc.test.MainActivity
E/jctest: onCreate: binding.recyclerView.context::class.java = class com.jc.test.MainActivity
E/jctest: onAttachedToRecyclerView: recyclerView.context::class.java = class com.jc.test.MainActivity
E/jctest: onCreateViewHolder: parent::class.java = class androidx.recyclerview.widget.RecyclerView
E/jctest: onCreateViewHolder: parent.context::class.java = class com.jc.test.MainActivity
E/jctest: onBindViewHolder: imageIv.context::class.java = class com.jc.test.MainActivity
通过 Log,真的就一目了然了,这四种方法虽然看着写法很不一样,但是其获取到的 context 其实都是同一个,那就是 MainActivity。
我们再来看看这四个方法:
- 2.1 通过 Adapter 构造函数传入 this,这很明显,就是 MainActivity。
- 2.2 通过 Parent.context 获取,通过 Log 我们可以知道,parent 就是 recylerView,所以获取的是 recyclerView 运行于的上下文,也就是 MainActivity。
- 2.3 通过 onAttachedToRecyclerView() 获取,也是获取 recyclerView 运行于的上下文,即 MainActivity。
- 2.4 通过 ImageView 获取,获取的是 ImageView 运行于的上下文,ImageView 是运行于 recyclerView 上的,所以获取的也是 MainActivity。
3.1 到底应该怎么用呢?
刚刚,我们通过打印 Log 知道了这四种方法获取到的 Context 其实都是同一个,那~~,这四种方法又该如何来取舍呢?到底用哪一种方法比较好呢?
文章开头中,我说 2.1 是我之前最常用的一个方法,那我现在为什么不用它了呢??
原因很简单,那就是因为之前我不知道可以直接在 Adapter 内部直接获取到 Context
如何在Adapter中正确的使用Context相关推荐
- jest.conf.js_如何在Jest中正确模拟Moment.js / dates
jest.conf.js by Iain Nash 由伊恩·纳什(Iain Nash) 如何在Jest中正确模拟Moment.js / dates (How to correctly mock Mom ...
- 如何在R中正确使用列表?
本文翻译自:How to Correctly Use Lists in R? Brief background: Many (most?) contemporary programming langu ...
- css中 media的用法,如何在css中正确使用@media
如何在css中使用@media作为特定分辨率?所以我想让我的侧栏更改取决于用户分辨率,所以我使用@media.如何在css中正确使用@media 这是示例代码: @media (max-width: ...
- java 中覆 写tostring_如何在Java中正确覆盖toString()?
如何在Java中正确覆盖toString()? 听起来有点愚蠢,但我需要帮助我的toString()方法,这是非常irking. 我尝试在网上查找,因为toString是搞砸了,"没有找到K ...
- MySQL中使用CASE出错,如何在MySQL中正确使用CASE..WHEN
如何在MySQL中正确使用CASE..WHEN 这里是一个演示查询,注意它非常简单,仅在base_price为0的位置获取,并且仍然select条件3: SELECT CASE course_enro ...
- python异步加载图片_如何在PyQt5中正确异步加载图像?
我在尝试如何在pyqtqlistview中正确地完成异步映像加载.在 我的主小部件由一个Qlistview和一个QLineEdit文本框组成. 我有一个参与者数据库,我使用QAbstractListM ...
- scarpy框架如何在crawl中正确传递自定义参数,scrapy.cmdline的execute为什么不能在while True中无限循环,execute换成crawl 方法
问题:scrapy.cmdline的execute函数执行完毕为什么一定会停,不能执行后面函数,也不在while True中无限循环(解决问题的结果 在最后) 我想让scrapy程序全年无休止运行,2 ...
- html界面出现 section,如何在HTML5中正确使用“ section”标签?
标记的正确方法是什么? 从技术上讲,两者都是正确的. 我要说的是,这两个示例看起来都不正确--但是很难用纯文本而不是真实上下文来说明,因为是语义标记,而不是像这样的通用包装. 您当然不应该有两个具有相 ...
- 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. wait, notify 和 noti ...
最新文章
- jquery checkbox勾选/取消勾选的诡异问题
- 《Hadoop MapReduce性能优化》一1.3 Hadoop MapReduce的工作原理
- 2019ICPC(南昌) - The Nth Item(矩阵快速幂)
- 音视频技术开发周刊 | 199
- 解决android studio引用远程仓库下载慢(JCenter下载慢)
- java 抽象类 final_final/抽象类/interface
- 1.请求安全-- MD5的必要性以及实际应用场景
- Maven依赖junit @Test报错解决
- 有个做微商的兄弟,他是卖品牌运动鞋的,最近很苦恼
- WannaCry反思:传统安全理念遭遇马奇诺防线式溃败
- 【转】简明 Python 教程
- 《罗辑思维》让知识交融做爱
- matlab 发动机万有特性,用MATLAB语言绘制发动机万有特性的两种方法
- hbase 查询固定条数_HBase统计表行数(RowCount)的四种方法
- 局域网远程控制工具之VNC
- c语言自动插桩,01 - LLVM Pass 实现 C函数 插桩
- 数字图像处理,相位相关算法解决图像的刚性平移问题
- 【STM32学习】(28)STM32实现光照度采集(标准库和HAL库实现)
- Redis(三)【五大数据类型三种特殊数据类型】
- java格式化XML文件
热门文章
- localhost 已拒绝连接(命令窗口安装版)还有安装教程
- mayavi实现kitti数据集可视化
- PigGo-安装及使用
- 夕食の後のレギュラーエクスプレスについての議論(1)
- 用户不小心忘记了密码,造成无法登录Windows2000 时怎么办?
- 计算机三级考试嵌入式系统重点精简汇总
- 西北工业大学与华为联合研发的首个面向飞行器的流体力学大模型“秦岭·翱翔”预发布
- sv中packed struct
- c语言while else语句用法,C语言注释C语言的主要功能else语句,while语句,dowhile语句,sw...
- 机器学习实战-57: 人工神经网络分类算法(Artificial Neural Network)