Android列表中元素的增加和删除
1.列表增加元素需要注意:
//局部刷新
mJokeAdapter.notifyItemInserted(int)
//只会更新从positionStart开始的itemCount的个数据变化,而之前的view和数据是不会发生变化的。
mJokeAdapter.notifyItemRangeInserted(positionStart, data.size)
2.列表中删除元素需要注意:
list.remove(i);
notifyItemRemoved(i);
//只会更新从positionStart开始的itemCount的个数据变化,而之前的view和数据是不会发生变化的。
notifyItemRangeChanged(i, list.size() - 1);
3.使用ListAdapter增加元素和删除元素:
//直接传入最新的元素进去
listAdapter.submitList(mList);
//增加元素就是:notifyItemRangeChanged(i, list.size() - 1);
notifyItemRemoved(i);
notifyItemRangeChanged(i, list.size() - 1);
4.解决更新数据的时候,列表的Item出现闪烁的问题:
01.使用局部刷新
//局部刷新
adapter.notifyItemChanged(position);
02.设置adapter的属性
//绑定adapter给RecycleView之前,设定adapter的stableIds为true
adapter.setHasStableIds(true);
03.给Item的position标记tag
@Override
public long getItemId(int position) {
return position;
}
5.列表删除元素的实例,逐个删除、批量删除:
01.逐个删除,调用列表的remove()方法,注意使用局部刷新notifyItemRemoved(i):
fun removeData(position: Int) {
list.removeAt(position)
notifyItemRemoved(position)
notifyItemChanged(0, list.size)
}
02.需要批量删除集合中的元素,集合的索引会在每一次删除元素的时候发生改变,因此需要及时改变索引值(否则会出现删除错乱的情况)
方案一:
//循环删除列表的元素,从后往前删,这样会动态改变集合的索引值,完美批量删除元素
for (int i = list.size() - 1; i >= 0; i--) {
//判定条件
if (tMap.get(i)) {
Log.i("hy55", "i = " + i);
Toast.makeText(this, "haha", Toast.LENGTH_SHORT).show();
list.remove(i);
}
}
//删除元素之后将新的列表传到RecyclerView之后
adapter.setData(list);
然后在Adapter中创建列表赋值的方法
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
private Context mContext;
private List<String>list;
private HashMap<Integer, Boolean> maps = new HashMap<Integer, Boolean>();//保存列表中每个item的选中状态
public RecyclerViewOnItemClickListener onItemClickListener;
public RecyclerViewAdapter(Context mContext, List<String> list) {
this.mContext = mContext;
this.list = list;
initMap();
}
//重新设置列表中的值
public void setData(List<String> list) {
this.list = list;
notifyDataSetChanged();
initMap();
}
方案二:
//使用迭代器,推荐
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
if (//TODO: 判定条件)
itr.remove();
}
6.列表去重的方法:
01.创建数据类
//data class官网介绍:https://kotlinlang.org/docs/data-classes.html
data class bean(
val name: String? = null,
val sex: String? = null
) {
//默认的equals()和hashCode()方法会比较所有的属性
//如果你重新定义了equals()和hashCode()方法,那么你设置的主键参数绝对不能为空,否则就会出现remove()方法删除不掉指定对象的情况
override fun equals(other: Any?): Boolean {
val bean = other as bean
//使用name作为判断addressListBean是否相同的元素
//使用name和sex都作为主键,那么只要两个参数都相等,这两个元素才相等
// return name == bean.name
return (name == bean.name && sex == bean.sex)
}
override fun hashCode(): Int {
return name.hashCode()
}
}
02.列表去重的逻辑
class MainActivity : AppCompatActivity() {
//创建一个存储数据的列表
// private var tempList: MutableList<bean> = mutableListOf()
private var tempList = ArrayList<bean>()
private var curList = ArrayList<bean>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main);
tempList.add(bean("aex", "girl", age = "12"))
curList.add(bean(age = "12"))
curList.add(bean(age = "13"))
findViewById<Button>(R.id.btn1).setOnClickListener {
Log.d("hy55", "删除之前tempList的值:$tempList")
Log.d("hy55", "curList:$curList")
//两个列表删除相同的元素
//错误:for (i in 0 until tempList.size)[for (i in tempList.indices)]:这种写法i会从0增加到2,但最后tempList的长度已经是1了,就会报错
// for (i in tempList.size - 1 downTo 0) {
// for (j in 0 until curList.size) {
// Log.i("hy55", "tempList.size=${tempList.size}、i=$i")
// if (curList[j].age == tempList[i].age) {
// tempList.removeAt(i)
// break
// }
// }
// }
// //两个列表删除相同的元素,使用迭代器,迭代器索引的起始位置是头元素的前面,所以iterator.next()就是列表的第一个元素
// val iterator = tempList.iterator()
// while (iterator.hasNext()) {
// val s = iterator.next()
// for (j in 0 until curList.size) {
// Log.i("hy55", "tempList.size=${tempList.size}")
// Log.i("hy55", "curList[j].age=${curList[j].age}")
// Log.i("hy55", "s.age=${s.age}")
// //如果for循环结束,没有满足条件的,for循环也会break
// if (curList[j].age == s.age) {
// //直接删除该索引下的值,tempList直接调用remove()方法删除了该元素,
// iterator.remove()
// //break退出for循环,因为删除元素的目的已经实现了,
// // 继续遍历,如果后续curList中还有满足条件的,但是该iterator已经remove()掉了,重复remove()就会报错
// break
// }
// }
// }
//两个列表删除相同的元素
// val list = ArrayList<bean>()
//
// for (i in 0 until tempList.size) {
// var flag = false
// for (j in 0 until curList.size) {
// //如果tempList中的元素和curList重叠了,那么就不会添加这个元素
// if(tempList[i].age == curList[j].age) {
// flag = true
// break
// }
// }
// if(!flag) {
// list.add(tempList[i])
// }
// }
// Log.d("hy55", "list:$list")
//两个列表,删除相同元素,通过打印可以看出forEach{}的原理就是从前往后遍历列表
curList.forEach{ it1 ->
Log.d("hy55", "it1=$it1")
for(i in tempList.size - 1 downTo 0) {
Log.d("hy55", "i=$i")
if(tempList[i].age == it1.age) {
tempList.removeAt(i)
Log.d("hy55", "tempList.size=${tempList.size}")
}
}
}
//删除所有的指定元素,只需要指定主键,列表会认为bean(name = "aex")和bean("aex", "girl")、bean("aex", "boy")相等
// for(i in 0 until tempList.size){
// tempList.remove(bean(name = "aex"))
// }
//改变某个元素的状态
// for(i in 0 until tempList.size){
// if (tempList[i].name == "tom"){
// tempList[i].sex = "girl"
// }
// }
//直接删掉第一个符合条件的元素,后面还有重复的元素也不会被删除,只有指定了主键,列表才会认为bean(name = "aex")和bean("aex", "girl")、bean("aex", "boy")相等
// tempList.remove(bean(name = "aex"))
//删除后面的重复元素,如果有重复的元素,保留前面的元素,删除后面的元素
// for(i in (tempList.size - 1) downTo 1){
// if(tempList[i].name == "aex") {
// tempList.removeAt(i)
// }
// }
//删除后面的重复元素,如果有重复的元素,保留前面的元素,删除后面的元素
// for(i in 0 until tempList.size){
// for (j in tempList.size - 1 downTo 1) {
// if(tempList[i].name == tempList[j].name) {
// Log.d("hy55", "$i、$j")
// //相当于tempList.remove(name = "aex"),直接删除第一个元素
tempList.remove(tempList[j])
// tempList.removeAt(j)
// Log.d("hy55", "删除之后tempList的值:$tempList")
// }
// }
// }
//删除后面的重复元素,如果有重复的元素,保留前面的元素,删除后面的元素
// for(i in 0 until tempList.size){
// for (j in i + 1 until tempList.size) {
// //只要主键相等,那么这两个元素就是相等的
// if(tempList[i].name == tempList[j].name) {
// Log.d("hy55", "$i、$j")
// //相当于tempList.remove(name = "aex"),直接删除第一个元素
tempList.remove(tempList[j])
// tempList.removeAt(j) //removeAt(j)是删除指定位置的元素,是可以生效的
// Log.d("hy55", "删除之后tempList的值:$tempList")
// }
// }
// }
//使用迭代器,删除所有的元素,原理是下标索引遍历,迭代器索引的起始位置是头元素的前面,所以iterator.next()就是列表的第一个元素
// val iter = tempList.iterator()
// while (iter.hasNext()) {
// val s = iter.next()
// //Log.i("hy55", "s1=${iter.next().age}"),此处崩溃的原因是iter.next()就会触发索引后移,
// // 前面(或者后面)已经有iter.next(),在log中的iter.next()也会触发索引后移,导致NoSuchElementException,索引超出了元素的长度
// if(s.age == "12") {
// iter.remove()
// }
// }
Log.d("hy55", "删除之后tempList的值:$tempList")
}
findViewById<Button>(R.id.btn2).setOnClickListener {
Log.d("hy55", "增加之前tempList的值:$tempList")
tempList.add(bean("tom", "boy"))
tempList.add(bean("aex", "boy", "13"))
Log.d("hy55", "增加之后tempList的值:$tempList")
}
}
}
03.布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/btn1"
android:text="删除"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btn2"
android:text="增加"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@+id/btn1"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
4.ArrayList的remove()方法源码,remove()方法自带循环遍历过程
public boolean remove(Object o) {
if (o == null) {
//循环遍历
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
//循环遍历
for (int index = 0; index < size; index++)
//使用equals()方法比较对象是否相等
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
//创建一个新的集合,去掉需要删除的元素
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}