技术标签: Context RecyclerView Adapter Android
最近我在项目中,发现一个同事写 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: Context
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
//在这里进行context的赋值
mContext = parent.context
val 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,还可以这么操作!!第一次见到这样的写法,有点意思,由此有了这一篇文章。
很多时候我们需要在 RecyclerView.Adapter 中使用到 context,比如:利用 Glide 来加载网络图片的时候。
这时,我们该如何拿到 context 给 Glide 呢?
这是我之前最常用的一种方式,通过 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.size
override 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
}
}
}
这个也是文章开头中提到的我的同事的一种写法,如下:
class MyAdapter(private val dataList: List<MyData>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private lateinit var mContext: Context
class MyViewHolder(val binding: RcyItemViewBinding) :
RecyclerView.ViewHolder(binding.root) {
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
mContext = parent.context
val binding = RcyItemViewBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return MyViewHolder(binding)
}
override fun getItemCount(): Int = dataList.size
override 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.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: Context
override 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.size
override 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
}
}
}
当当就我们举的这个例子,因为我们需要用到 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.size
override 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
}
}
}
上面介绍了四种方法来获取 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.size
override 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。
我们再来看看这四个方法:
刚刚,我们通过打印 Log 知道了这四种方法获取到的 Context 其实都是同一个,那~~,这四种方法又该如何来取舍呢?到底用哪一种方法比较好呢?
文章开头中,我说 2.1 是我之前最常用的一个方法,那我现在为什么不用它了呢??
原因很简单,那就是因为之前我不知道可以直接在 Adapter 内部直接获取到 Context ,既然可以在类内部直接获取到的参数,完全就没有必要再写一个参数从外部导入,这样会让代码看着更加的简洁。
还记得文章中留的那个疑问吗 -> 有人说通过 2.2 parent.context 方法获取 context 会导致内存泄漏,你认同吗?
该写法不会导致内存泄漏,但是我也不推荐这样的写法,毕竟
onCreateViewHolder()
方法的执行次数是由 itemCount 所决定的,所以也就意味着mContext = parent.context
也会执行 itemCount 次,明明一次就行,其它多余的操作,会造成不必要的开销。
那通过 onAttachedToRecyclerView() 方法,只会进行一次赋值操作,很OK啊,但毕竟他又是定义全局变量,又是覆写方法,太麻烦了,我们可以在简单一点。
好像我把前面介绍的方法都给否认了,那我现在是怎么用的呢?还是以上面的例子,如下:
class MyAdapter(private val dataList: List<MyData>) :
RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
class MyViewHolder(
private val context: Context,
private val binding: RcyItemViewBinding
) :
RecyclerView.ViewHolder(binding.root) {
fun bind(data: MyData) {
Glide.with(context).load(data.imageUrl).into(binding.imageIv)
binding.contentTv.text = data.content
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding = RcyItemViewBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return MyViewHolder(parent.context, binding)
}
override fun getItemCount(): Int = dataList.size
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(dataList[position])
}
}
我选择在 onCreateViewHolder()
通过 parent.context
方法获取 context,但是,不是赋值给全部变量 mContext,而是直接传给 ViewHolder
作为一个私有变量供其使用。
文章中的看法都是我自己的个人观点,毕竟对于一个方法的好坏,就看你站在什么角度看待它,我并没有认为我的方法是最好的最值得推荐的,从而要求大家也这么写。相反,写这篇文章,纯粹就是觉得很有意思,因为文章中的介绍的这几种方法都是我身边出现的,我特想知道大家是用什么方式的呢?欢迎大家留言与我一起讨论。
其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。 另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!
最近翻看技术文章,发现一个叫做disruptor的高性能内存队列占据了头版头条,好奇其高性能的秘密,于是对该框架进行了一些简单的研究。disruptor并非新出,而是从2013年到现在经历了3个大版本的迭代。本文有如下几个部分:disruptor如何使用?disruptor高性能的秘密?如何使用核心概念:EventFactory:用于生成一个事件提供消费者消费EventHandler:消费者处理器..._java中eventfactory
1、被注解的类 @Autowired private TfaAlarmDao tfaAlarmDao;2、取注解类ApplicationContext app = new FileSystemXmlApplicationContext("classpath:appContext-service-mockalarm.xml"); tfaAlarm
Java操作ElasticSearch①. 创建Java项目导入maven依赖②. 创建索引和类型1. 创建客户端操作对象2. 创建索引3. 删除索引4. 创建索引和类型③. 索引中创建文档④. 更新一条索引⑤. 删除一条索引⑥. 批量操作⑦. 查询操作1. 查询所有并排序2. term查询3. rang查询4. 分页查询5. 查询返回指定字段6. prefix 前缀查询7. wildcardQuery 通配符查询8. ids 多id查询9. fuzzy 模糊查询10. bool 布尔查询11. hi
想要把自己旅行的照片,或者宝宝成长的照片,即将结婚的婚纱照,再或者年会上要用的员工活动照,做成类似电子相册的视频出来,给领导同事家人朋友们分享,但是却苦于视频剪辑软件的繁琐复杂,不知如何下手吗,今天就给大家分享一个小网站,99mv,只需简单的三步,零技术要求,即可做成自己的视频大片,效果或酷炫或唯美,各种风格,绝对的高大上。制作前准备:当然是照片要全部挑选好(一般的_视频制作的详细步骤
把微软代码搬到BSP下调试的方法(作者 gooogleman foxmail com )
/ etc / crontab文件具有以下权限:-rw-R – R–我知道这个文件是用于系统cron作业的,其他用户不应该有权修改它.当前权限允许所有用户读取对文件的访问权限,使他们能够查看内容.是否有必要让所有用户都能读取/ etc / crontab?我相信所有用户都不应该知道一些管理命令,所以将权限更改为-rw-r —–不是更好吗?我使用了CentOS的权限字符串,并没有在其他发行版上测..._开启crontab权限
本文只先简单的介绍下Spring中的事务与DB中锁的关系。首先总结:Spring事务的实现本质上是使用的DB中的事务,而DB中的事务实现又主要依靠DB中的锁。所以spring事务本质上使用数据库锁,开启spring事务意味着使用数据库锁。所以大家一定要厘清DB事务与DB各种锁的原理与概念。后续我也研究一下DB锁,并结合具体的生产环境监控数据来谈谈。《以下是转载部分内容。主要是Spring事务的使用..._spring事务的锁
vpaVariable precision arithmetic变量精度计算SyntaxR =vpa(A)R =vpa(A, d)DescriptionR =vpa(A)uses variable-precision arithmetic (VPA) to compute each element ofAtoddecimal digits of accuracy, whered..._matlab vpa无法转换数值
通过域计算机开机脚本统一修改客户端本地管理员密码即可:strComputer = "."Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, user")objUser.SetPassword "123456789"objUser.SetInfo ...
前馈神经网络Feedforward Neural Network网络结构(一般分两种)Back Propagation Networks - 反向传播网络RBF networks - 径向基函数神经网络BP网络是所有的神经网络中结构最为简单的一种网络。一般我们习惯把网络画成左边输入右边输出层的...
一、概述Gradle是一款优秀的构建系统工具,它是基于Groovy的DSL语言实现,Gradle在Android中具有很重要的位置,因此在学习Gradle之前,了解Groovy是必须的。Groovy是基于JVM虚拟机的一种动态语言,与Java非常类似,因此Java学习者入门Groovy基本没有任何障碍,并且Groovy完全兼容Java。1)Groovy之字符串1、在Java中,每条..._groovy 分号
数据要好好造,特别是出题时#pragma GCC optimize(3)#include<bits/stdc++.h>using namespace std;#define maxn (1 << 22)#define rep(i,l,r) for(register int i = l ; i <= r ; i++)#define repd(i,r,l) ...