1、
ListView的内存优化机制
第一:RecycleBin机制
在ListView里有一个内部类RecycleBin ,RecycleBin 里有一个存储View对象的ArrayList
private ArrayList<View> mCurrentScrap;
当有item滑出了屏幕,itemView会被回收到这个数组里,而有新的item滑入了屏幕时,会从数组里拿到view,这个view做为第二个参数传到了Adapter的getView()方法当中,这样就不用每一次都inflate view了。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId, null);
} else {
view = convertView;
}
return view;
}
第二:ViewHolder
ListView内部的重用是防止你重复inflate布局,ViewHolder的使用是防止你重复findViewById。
例:
public class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//分离绑定职责
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(resourceId, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.bind(getItem(position));
return convertView;
}
class ViewHolder {
private TextView subView1;
private TextView subView2;
ViewHolder(View root){//通过构造方法将子view的查找逻辑搬移到这里
subView1 = (TextView)root.findViewById(R.id1);
subView2 = (TextView)root.findViewById(R.id2);
}
void bind(ItemData item){
//绑定逻辑搬移到这里将更加简洁
subView1.setText(item.text1);
subView2.setText(item.text2);
}
}
}
2、
ViewHolder是用来保存视图引用的类,无论是ListView亦或是RecyclerView。只不过在ListView中,ViewHolder需要自己来定义,且这只是一种推荐的使用方式,不使用当然也可以,这不是必须的。只不过不使用ViewHolder的话,ListView每次getView的时候都会调用findViewById(int),这将导致ListView性能展示迟缓。而在RecyclerView中使用RecyclerView.ViewHolder则变成了必须,尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题。
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount(){
return mDatas.size();
}
class MyViewHolder extends ViewHolder{
TextView tv;
public MyViewHolder(View view){
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
3、
在ListView中如果我们想要在item之间添加间隔符,我们只需要在布局文件中对ListView添加如下属性即可:
android:divider="@android:color/transparent"
android:dividerHeight="5dp"
而RecyclerView并没有支持divider这样的属性,但是可以自己定制:
我们可以通过该方法添加分割线:
mRecyclerView.addItemDecoration();
该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类。
4、
我们知道ListView只能在垂直方向上滚动,Android API没有提供ListView在水平方向上面滚动的支持。或许有多种方式实现水平滑动,但是请相信我,ListView并不是设计来做这件事情的。但是RecyclerView相较于ListView,在滚动上面的功能扩展了许多。它可以支持多种类型列表的展示要求,主要如下:
LinearLayoutManager,可以支持水平和竖直方向上滚动的列表。
StaggeredGridLayoutManager,可以支持交叉网格风格的列表,类似于瀑布流或者Pinterest。
GridLayoutManager,支持网格展示,可以水平或者竖直滚动,如展示图片的画廊。
使用如下:
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
5、
RecyclerView 的item增加、删除的动画是可配置的:RecyclerView.ItemAnimator。
ItemAnimator是一个抽象类,系统为我们提供了一种默认的实现类DefaultItemAnimator。
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
6、
ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。
除了这种方式也可以通过adapter中自己去提供回调,如:
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>{
//...
public interface OnItemClickLitener{
void onItemClick(View view, int position);
void onItemLongClick(View view , int position);
}
private OnItemClickLitener mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener){
this.mOnItemClickLitener = mOnItemClickLitener;
}
@Override
public void onBindViewHolder(final MyViewHolder holder, final int position){
holder.tv.setText(mDatas.get(position));
// 如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null){
holder.itemView.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.itemView, pos);
}
});
holder.itemView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v){
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.itemView, pos);
return false;
}
});
}
}
//...
}
别忘了给item添加一个drawable:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:state_pressed="true" android:drawable="@color/color_item_press"></item>
<item android:drawable="@color/color_item_normal"></item>
</selector>
Activity中去设置监听:
mAdapter.setOnItemClickLitener(new OnItemClickLitener() {
@Override
public void onItemClick(View view, int position){
Toast.makeText(HomeActivity.this, position + " click",
Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position){
Toast.makeText(HomeActivity.this, position + " long click",
Toast.LENGTH_SHORT).show();
mAdapter.removeData(position);
}
});
7、
ListView可以设置选择模式,并添加MultiChoiceModeListener,如下所示:
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public boolean onCreateActionMode(ActionMode mode, Menu menu) { ... }
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) { ... }
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_crime:
CrimeAdapter adapter = (CrimeAdapter)getListAdapter();
CrimeLab crimeLab = CrimeLab.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {
if (getListView().isItemChecked(i)) {
crimeLab.deleteCrime(adapter.getItem(i));
}
}
mode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { ... }
public void onDestroyActionMode(ActionMode mode) { ... }
});
而RecyclerView则没有此功能。