如何在Recyclerview中使用recyclerview
how to recycle view in Recycler View
我正在使用 Recycler 视图创建列表视图。在列表视图中,每个项目都有水平滚动条。在水平滚动条中,我根据特定的业务逻辑显示一项或三项。列出后,前 2 个卷轴显示的正是我想要的。但是对于进一步的滚动,我在水平滚动视图中显示的项目有问题。它显示多个项目,其中只有一个项目应该在那里。查了一下才知道是因为view没有被回收
经过搜索,我重写了这个函数,onViewRecycled。这个函数在问题开始时被调用(第三个和更多的卷轴)。我不知道如何解决这个问题。我在开始时将历史列表传递给适配器。
请帮我解决这个问题。
public class HistoryAdapter(users:List<HistoryItem>): RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {
val TAG = "HistoryAdapter"
var historyList:List<HistoryItem>? =null
var context: Context? =null
init {
historyList = users
}
override fun onViewRecycled(holder: ViewHolder?) {
super.onViewRecycled(holder)
Log.d(TAG,"********************************************************************************************************************************Views are recycled****************************")
if (holder is HistoryAdapter.ViewHolder) {
val handler = Handler()
handler.post(Runnable { () -> notifyItemRemoved(holder.getOldPosition()) })
//notifyItemRangeChanged(holder.getAdapterPosition(),historyList!!.size())
}
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
var lung: Boolean? = false
var tag: String? = null
val historyItem: HistoryItem = historyList!!.get(position)
holder!!.profileImg.setImageBitmap(BitmapFactory.decodeFile(File(Environment.getDataDirectory().getAbsolutePath(), "data/" + context!!.getPackageName() + "/files/users/" + historyItem.uuidVal + "/portrait.png").getAbsolutePath()))
holder!!.notesTxt.setText(historyItem.sessionVal!!.getNote())
val date = historyItem.sessionVal!!.getDate()
var formatDayOfMonth = SimpleDateFormat("dd");
val day = Integer.parseInt(formatDayOfMonth.format(date));
val dayStr = day.toString();
formatDayOfMonth = SimpleDateFormat("MMM")
val month = formatDayOfMonth.format(date)
formatDayOfMonth = SimpleDateFormat("yyyy")
val year = formatDayOfMonth.format(date)
formatDayOfMonth = SimpleDateFormat("hh:mm a")
val currentTime = formatDayOfMonth.format(date)
val dateStr = month+" "+dayStr+", "+year
holder!!.dateTxt.setText(dateStr)
holder!!.timeTxt.setText(currentTime)
Log.d(TAG,"********************************************************************************************************************************************user =>"+historyItem.uuidVal);
Log.d(TAG,"********************************************************************************************************************************************current time =>"+currentTime);
var ambientTemp: Double? = null
var surfaceTemp: Double? = null
var coreBodyTemp: Double? = null
var heartRate: Int? = null
var lungAvailable: Boolean = false
var heartAvailable: Boolean = false
var tempAvailable: Boolean = false
try {
val tempRecording:TemperatureRecording = checkNotNull(historyItem.sessionVal!!.getTemperature())
tempAvailable = true
ambientTemp = tempRecording.getAmbientTemp()
surfaceTemp = tempRecording.getSurfaceTemp()
coreBodyTemp = TemperatureRecording.CalculateCoreBodyTemperature.getCoreBodyTemp(ambientTemp,surfaceTemp)
} catch(i: IllegalStateException) {
Log.w(TAG,"Temperature not available for user session")
tempAvailable = false
}
try {
val heartRecording:HeartRecording = checkNotNull(historyItem.sessionVal!!.getHeart())
heartAvailable = true
heartRate = heartRecording.getHeartRate()
} catch(i: IllegalStateException) {
Log.w(TAG,"Heart not available for user session")
heartAvailable = false
}
try {
val lungRecording:LungsRecording = checkNotNull(historyItem.sessionVal!!.getLungs())
lungAvailable = true
} catch(i: IllegalStateException) {
Log.w(TAG,"Lung not available for user session")
lungAvailable = false
}
Log.d(TAG,"********************************************************************************************************************************************temperature =>"+tempAvailable)
Log.d(TAG,"********************************************************************************************************************************************heart =>"+heartAvailable)
Log.d(TAG,"********************************************************************************************************************************************lung =>"+lungAvailable)
//Log.d(TAG,"********************************************************************************************************************************************ambient temp val =>"+ambientTemp)
//Log.d(TAG,"********************************************************************************************************************************************surface temp val =>"+surfaceTemp)
//Log.d(TAG,"********************************************************************************************************************************************heart val =>"+heartRate)
//Log.d(TAG,"********************************************************************************************************************************************lung val =>"+historyItem.sessionVal!!.getLungs())
val parentLinearLayout = holder!!.readingsView
//createLayout(holder!!.readingsView,tag,coreBodyTemp,heartRate)
var childLinearLayout: LinearLayout? = null
if(tempAvailable == true && heartAvailable == true && lungAvailable == true) {
for(i in 1..3) {
if(i == 1) {
val df = DecimalFormat("#.##");
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if(i == 2) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if(i == 3) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
}
}
} else if (tempAvailable) {
val df = DecimalFormat("#.##");
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if (heartAvailable) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if (lungAvailable) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
}
}
fun createChildView(icon: Bitmap,readingVal: String, readingTag: String) : LinearLayout {
val lp = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
lp.weight = 1f
val parent: LinearLayout = LinearLayout(context!!)
parent.setOrientation(LinearLayout.HORIZONTAL)
parent.setLayoutParams(lp)
val imageView = ImageView(context!!)
val layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams.weight = 0.4f
layoutParams.leftMargin = 10
layoutParams.rightMargin = 10
layoutParams.topMargin = 10
layoutParams.bottomMargin =10
imageView.setLayoutParams(layoutParams)
imageView.setImageBitmap(icon)
parent.addView(imageView)
val readingLayout = LinearLayout(context!!)
readingLayout.setOrientation(LinearLayout.VERTICAL)
val lp1 = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
lp1.weight = 0.6f
lp1.topMargin = 10
readingLayout.setLayoutParams(lp)
val displayValue = TextView(context!!)
val layoutParams1 = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 0)
layoutParams1.weight = 0.7f
displayValue.setLayoutParams(layoutParams1)
displayValue.setText(readingVal)
readingLayout.addView(displayValue)
val displayTag = TextView(context!!)
layoutParams1.weight = 0.3f
displayTag.setLayoutParams(layoutParams1)
displayTag.setText(readingTag)
readingLayout.addView(displayTag)
parent.addView(readingLayout)
return parent
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder? {
context = parent!!.getContext()
// create a new view
val v: View = LayoutInflater.from(parent!!.getContext())
.inflate(R.layout.layout_history_row, parent, false);
return ViewHolder(v)
}
override fun getItemCount(): Int {
return historyList!!.size()
}
public class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
public var profileImg: ImageView
public var dateTxt: TextView
public var timeTxt: TextView
public var locationTxt: TextView
public var notesTxt: TextView
//public var icon: ImageView
//public var readingTxt: TextView
//public var readingDescTxt: TextView
public var readingsView: LinearLayout
init {
profileImg = itemView.findViewById(R.id.profileImage) as ImageView
dateTxt = itemView.findViewById(R.id.date) as TextView
timeTxt = itemView.findViewById(R.id.time) as TextView
locationTxt = itemView.findViewById(R.id.location) as TextView
notesTxt = itemView.findViewById(R.id.notes) as TextView
//readingTxt = itemView.findViewById(R.id.readings) as TextView
//readingDescTxt = itemView.findViewById(R.id.readingsDesc) as TextView
// icon = itemView.findViewById(R.id.icon) as ImageView
readingsView = itemView.findViewById(R.id.readingsView) as LinearLayout
}
}
}
Activity代码
val history = findViewById(R.id.history) as RecyclerView
for(user in allUsers) {
val uuid: String? = user.getId()
Log.d(TAG,"*****************************************************************************************************************UUID=>"+uuid+"FirstName=>"+user.getFirstName()+",sessions size =>"+user.getSessions().size())
for(session in user.getSessions()) {
historyItems.add(HistoryItem(user.getId(),session))
}
}
history.setHasFixedSize(true);
history.setAdapter(HistoryAdapter(historyItems))
history.setLayoutManager(LinearLayoutManager(this))
我不知道你期待什么样的 "recycling",但 RecyclerView 所做的是它会调用 onCreateViewHolder()
直到它有足够的 viewholders 来覆盖比实际内容略多的内容在屏幕上可见。
然后它将调用 onBindViewHolder()
来填充创建的视图持有者中的数据。
当您开始滚动时,它会抓取一个已创建的视窗,并使用新的 position
将其反馈到 onBindViewHolder()
。它不会对取景器进行任何神奇的重置。
在您的情况下,您永远不会重置 readingsView
,因此适配器不断向其添加子项(这就是为什么当您进一步滚动浏览数据时它包含的子项比预期的多)。在 onBindViewHolder()
中,您需要先从 readingsView
中删除所有现有子项,然后再开始添加新子项。
我正在使用 Recycler 视图创建列表视图。在列表视图中,每个项目都有水平滚动条。在水平滚动条中,我根据特定的业务逻辑显示一项或三项。列出后,前 2 个卷轴显示的正是我想要的。但是对于进一步的滚动,我在水平滚动视图中显示的项目有问题。它显示多个项目,其中只有一个项目应该在那里。查了一下才知道是因为view没有被回收
经过搜索,我重写了这个函数,onViewRecycled。这个函数在问题开始时被调用(第三个和更多的卷轴)。我不知道如何解决这个问题。我在开始时将历史列表传递给适配器。
请帮我解决这个问题。
public class HistoryAdapter(users:List<HistoryItem>): RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {
val TAG = "HistoryAdapter"
var historyList:List<HistoryItem>? =null
var context: Context? =null
init {
historyList = users
}
override fun onViewRecycled(holder: ViewHolder?) {
super.onViewRecycled(holder)
Log.d(TAG,"********************************************************************************************************************************Views are recycled****************************")
if (holder is HistoryAdapter.ViewHolder) {
val handler = Handler()
handler.post(Runnable { () -> notifyItemRemoved(holder.getOldPosition()) })
//notifyItemRangeChanged(holder.getAdapterPosition(),historyList!!.size())
}
}
override fun getItemId(position: Int): Long {
return super.getItemId(position)
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
var lung: Boolean? = false
var tag: String? = null
val historyItem: HistoryItem = historyList!!.get(position)
holder!!.profileImg.setImageBitmap(BitmapFactory.decodeFile(File(Environment.getDataDirectory().getAbsolutePath(), "data/" + context!!.getPackageName() + "/files/users/" + historyItem.uuidVal + "/portrait.png").getAbsolutePath()))
holder!!.notesTxt.setText(historyItem.sessionVal!!.getNote())
val date = historyItem.sessionVal!!.getDate()
var formatDayOfMonth = SimpleDateFormat("dd");
val day = Integer.parseInt(formatDayOfMonth.format(date));
val dayStr = day.toString();
formatDayOfMonth = SimpleDateFormat("MMM")
val month = formatDayOfMonth.format(date)
formatDayOfMonth = SimpleDateFormat("yyyy")
val year = formatDayOfMonth.format(date)
formatDayOfMonth = SimpleDateFormat("hh:mm a")
val currentTime = formatDayOfMonth.format(date)
val dateStr = month+" "+dayStr+", "+year
holder!!.dateTxt.setText(dateStr)
holder!!.timeTxt.setText(currentTime)
Log.d(TAG,"********************************************************************************************************************************************user =>"+historyItem.uuidVal);
Log.d(TAG,"********************************************************************************************************************************************current time =>"+currentTime);
var ambientTemp: Double? = null
var surfaceTemp: Double? = null
var coreBodyTemp: Double? = null
var heartRate: Int? = null
var lungAvailable: Boolean = false
var heartAvailable: Boolean = false
var tempAvailable: Boolean = false
try {
val tempRecording:TemperatureRecording = checkNotNull(historyItem.sessionVal!!.getTemperature())
tempAvailable = true
ambientTemp = tempRecording.getAmbientTemp()
surfaceTemp = tempRecording.getSurfaceTemp()
coreBodyTemp = TemperatureRecording.CalculateCoreBodyTemperature.getCoreBodyTemp(ambientTemp,surfaceTemp)
} catch(i: IllegalStateException) {
Log.w(TAG,"Temperature not available for user session")
tempAvailable = false
}
try {
val heartRecording:HeartRecording = checkNotNull(historyItem.sessionVal!!.getHeart())
heartAvailable = true
heartRate = heartRecording.getHeartRate()
} catch(i: IllegalStateException) {
Log.w(TAG,"Heart not available for user session")
heartAvailable = false
}
try {
val lungRecording:LungsRecording = checkNotNull(historyItem.sessionVal!!.getLungs())
lungAvailable = true
} catch(i: IllegalStateException) {
Log.w(TAG,"Lung not available for user session")
lungAvailable = false
}
Log.d(TAG,"********************************************************************************************************************************************temperature =>"+tempAvailable)
Log.d(TAG,"********************************************************************************************************************************************heart =>"+heartAvailable)
Log.d(TAG,"********************************************************************************************************************************************lung =>"+lungAvailable)
//Log.d(TAG,"********************************************************************************************************************************************ambient temp val =>"+ambientTemp)
//Log.d(TAG,"********************************************************************************************************************************************surface temp val =>"+surfaceTemp)
//Log.d(TAG,"********************************************************************************************************************************************heart val =>"+heartRate)
//Log.d(TAG,"********************************************************************************************************************************************lung val =>"+historyItem.sessionVal!!.getLungs())
val parentLinearLayout = holder!!.readingsView
//createLayout(holder!!.readingsView,tag,coreBodyTemp,heartRate)
var childLinearLayout: LinearLayout? = null
if(tempAvailable == true && heartAvailable == true && lungAvailable == true) {
for(i in 1..3) {
if(i == 1) {
val df = DecimalFormat("#.##");
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if(i == 2) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if(i == 3) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
}
}
} else if (tempAvailable) {
val df = DecimalFormat("#.##");
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.temperature), df.format(coreBodyTemp).toString(), context!!.getString(R.string.temperatureStr))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if (heartAvailable) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.heart), heartRate.toString(), context!!.getString(R.string.heartRate))
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
} else if (lungAvailable) {
childLinearLayout = createChildView(BitmapFactory.decodeResource(context!!.getResources(),R.drawable.lung), "", "")
parentLinearLayout.addView(childLinearLayout)
childLinearLayout = null
}
}
fun createChildView(icon: Bitmap,readingVal: String, readingTag: String) : LinearLayout {
val lp = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
lp.weight = 1f
val parent: LinearLayout = LinearLayout(context!!)
parent.setOrientation(LinearLayout.HORIZONTAL)
parent.setLayoutParams(lp)
val imageView = ImageView(context!!)
val layoutParams = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams.weight = 0.4f
layoutParams.leftMargin = 10
layoutParams.rightMargin = 10
layoutParams.topMargin = 10
layoutParams.bottomMargin =10
imageView.setLayoutParams(layoutParams)
imageView.setImageBitmap(icon)
parent.addView(imageView)
val readingLayout = LinearLayout(context!!)
readingLayout.setOrientation(LinearLayout.VERTICAL)
val lp1 = LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT)
lp1.weight = 0.6f
lp1.topMargin = 10
readingLayout.setLayoutParams(lp)
val displayValue = TextView(context!!)
val layoutParams1 = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 0)
layoutParams1.weight = 0.7f
displayValue.setLayoutParams(layoutParams1)
displayValue.setText(readingVal)
readingLayout.addView(displayValue)
val displayTag = TextView(context!!)
layoutParams1.weight = 0.3f
displayTag.setLayoutParams(layoutParams1)
displayTag.setText(readingTag)
readingLayout.addView(displayTag)
parent.addView(readingLayout)
return parent
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder? {
context = parent!!.getContext()
// create a new view
val v: View = LayoutInflater.from(parent!!.getContext())
.inflate(R.layout.layout_history_row, parent, false);
return ViewHolder(v)
}
override fun getItemCount(): Int {
return historyList!!.size()
}
public class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
public var profileImg: ImageView
public var dateTxt: TextView
public var timeTxt: TextView
public var locationTxt: TextView
public var notesTxt: TextView
//public var icon: ImageView
//public var readingTxt: TextView
//public var readingDescTxt: TextView
public var readingsView: LinearLayout
init {
profileImg = itemView.findViewById(R.id.profileImage) as ImageView
dateTxt = itemView.findViewById(R.id.date) as TextView
timeTxt = itemView.findViewById(R.id.time) as TextView
locationTxt = itemView.findViewById(R.id.location) as TextView
notesTxt = itemView.findViewById(R.id.notes) as TextView
//readingTxt = itemView.findViewById(R.id.readings) as TextView
//readingDescTxt = itemView.findViewById(R.id.readingsDesc) as TextView
// icon = itemView.findViewById(R.id.icon) as ImageView
readingsView = itemView.findViewById(R.id.readingsView) as LinearLayout
}
}
}
Activity代码
val history = findViewById(R.id.history) as RecyclerView
for(user in allUsers) {
val uuid: String? = user.getId()
Log.d(TAG,"*****************************************************************************************************************UUID=>"+uuid+"FirstName=>"+user.getFirstName()+",sessions size =>"+user.getSessions().size())
for(session in user.getSessions()) {
historyItems.add(HistoryItem(user.getId(),session))
}
}
history.setHasFixedSize(true);
history.setAdapter(HistoryAdapter(historyItems))
history.setLayoutManager(LinearLayoutManager(this))
我不知道你期待什么样的 "recycling",但 RecyclerView 所做的是它会调用 onCreateViewHolder()
直到它有足够的 viewholders 来覆盖比实际内容略多的内容在屏幕上可见。
然后它将调用 onBindViewHolder()
来填充创建的视图持有者中的数据。
当您开始滚动时,它会抓取一个已创建的视窗,并使用新的 position
将其反馈到 onBindViewHolder()
。它不会对取景器进行任何神奇的重置。
在您的情况下,您永远不会重置 readingsView
,因此适配器不断向其添加子项(这就是为什么当您进一步滚动浏览数据时它包含的子项比预期的多)。在 onBindViewHolder()
中,您需要先从 readingsView
中删除所有现有子项,然后再开始添加新子项。