复杂ListView及多层嵌套界面卡顿问题终极解决NoCacheListView
程序员文章站
2022-03-31 08:05:29
ListView是Android曾经也是现在最常用的控件,item复用和界面卡顿等问题伴随着ListView一直没有断过,后来RecyclerView的出现解决了一些缓存复用的问题,确实RecyclerView拥有一套比较完善的缓存机制。但是我们今天的主角不是它,而是一个全新的控件。 有些时候我需要列表中在滑动的时候,一个view都不要重新绘制,我不需要item之间的相互复用,这样的情况下,外层一个ScrollView,里面一个LinearLayout,似乎就满足的条件,但是单纯的Line......
ListView是Android曾经也是现在最常用的控件,item复用和界面卡顿等问题伴随着ListView一直没有断过,后来RecyclerView的出现解决了一些缓存复用的问题,确实RecyclerView拥有一套比较完善的缓存机制。但是我们今天的主角不是它,而是一个全新的控件。 有些时候我需要列表中在滑动的时候,一个view都不要重新绘制,我不需要item之间的相互复用,这样的情况下,外层一个ScrollView,里面一个LinearLayout,似乎就满足的条件,但是单纯的LinearLayout去当做ListView使用的时候还是要自己写不少逻辑。这次文章介绍的就是已经写好的一个自定义LinearLayout,完全可以当做一个无缓存的ListView使用,子界面不去频繁的重绘,就节省了很大一笔内存开销,界面滑动就会流畅,再复杂的列表嵌套,经测试也不会卡顿。好了,闲话少说,咱们直接看代码,首先就是重要的自定义控件NoCacheListView。
代码比较简洁,大家稍微看下,里面包含的配套的setAdapter方法,这是大家比较关心的,此类提供了两种,
1、setAdapter(),这个需要自己定义一个类继承本类中提供的Adapter,或者直接new NoCacheListView.Adapter()也可以;
2、setAdapter2(),这个方法就可以使用我们平时用的Adapter,也就是继承android.widget.BaseAdapter的适配器;
下面是NoCacheListView的完整代码,可以直接使用,
public class NoCacheListView extends LinearLayout implements View.OnClickListener {
boolean mLayoutFrozen = false;
private OnItemClickListener mListener;
private Adapter<?> mAdapter;
private android.widget.BaseAdapter mAdapter2;
private DataSetObserver mDataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
refreshLayout();
}
@Override
public void onInvalidated() {
super.onInvalidated();
}
};
private static final int INVALID_POSITION = -1;
public NoCacheListView(Context context) {
this(context, null);
}
public NoCacheListView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public NoCacheListView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOrientation(LinearLayout.VERTICAL);
}
public void setAdapter(Adapter<?> adapter) {
if (adapter == null) {
return;
}
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
mAdapter = adapter;
mAdapter.registerDataSetObserver(mDataSetObserver);
refreshLayout();
}
/**
* 支持通用BaseAdapter支持
* 由于此View无缓存,getView中的convertView始终为null
* @param adapter
*/
public void setAdapter2(android.widget.BaseAdapter adapter) {
if (adapter == null) {
return;
}
if (mAdapter2 != null && mDataSetObserver != null) {
mAdapter2.unregisterDataSetObserver(mDataSetObserver);
}
mAdapter2 = adapter;
mAdapter2.registerDataSetObserver(mDataSetObserver);
refreshLayout();
}
private void refreshLayout() {
mLayoutFrozen = false;
removeAllViews();
if (mAdapter != null && mAdapter.getCount() > 0) {
for (int i = 0; i < mAdapter.getCount(); i++) {
addView(mAdapter.getView(this, i));
}
refreshListener();
} else if (mAdapter2 != null && mAdapter2.getCount() > 0) {
for (int i = 0; i < mAdapter2.getCount(); i++) {
addView(mAdapter2.getView(i, null, this));
}
refreshListener();
}
requestLayout();
}
private void refreshListener() {
if (mListener != null) {
int childCount = getChildCount();
if (childCount > 0) {
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
view.setOnClickListener(this);
}
}
}
}
public void setOnItemClickListener(OnItemClickListener listener) {
if (listener != null) {
mListener = listener;
}
refreshListener();
}
@Override
public void onClick(View v) {
int position = getPositionForView(v);
if (position == INVALID_POSITION || (mAdapter == null && mAdapter2 == null)) {
// Cannot perform actions on invalid items.
return;
}
mListener.onItemClick(v, position);
}
public int getPositionForView(View view) {
View listItem = view;
try {
View v;
while ((v = (View) listItem.getParent()) != null && !v.equals(this)) {
listItem = v;
}
} catch (ClassCastException e) {
// We made it up to the window without find this list view
return INVALID_POSITION;
}
// Search the children for the list item
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
if (getChildAt(i).equals(listItem)) {
return i;
}
}
// Child not found!
return INVALID_POSITION;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public static abstract class Adapter<T> {
private final DataSetObservable mDataSetObservable = new DataSetObservable();
private void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
private void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
/**
* 获取当前条目类型
* @param position 当前位置
* @return
*/
public abstract int getItemViewType(int position);
/**
* 获取展示条目总数
* @return
*/
public abstract int getCount();
/**
* 获取当前条目对象
* @param position 当前位置
* @return
*/
public abstract T getItem(int position);
/**
* 获取要渲染的View
* @param parent 父布局
* @param position 当前位置
* @return
*/
public abstract View getView(ViewGroup parent, int position);
}
}
本文地址:https://blog.csdn.net/qiqigeermumu/article/details/110188797
上一篇: 蓝桥杯2017JAVA_B省赛真题详解
下一篇: 优先队列