Android Adapter优化问题
最近在使用BaseAdapter显示录制的视频文件时,又是遇到了各种奇葩问题。比如:
1>文件个数多时,快速上下滑动时,速度明显缓慢,有点卡,更坑的是会出现异常退出;
2>checkBox 点击选择时,其它页面的相同位置的checkBox也会被选中;
3>自定义的checkBox的图标太小,如何增大checkBox的点击区域;
4>进行加锁操作后,往缩列图中添加加锁文字,并不能得到及时的更新等情况。
当然不得不说的是,出现这些问题的确是因为自己对adapter的理解不够深入,也一直没有注意这些问题,之前用的还是好好的,所以也就没有太在意,直到这次遇到问题了,不解决不行。
下面先贴上项目中用到的adapter类,再慢慢分析:
public FilePageAdapter(List<HashMap<String, Object>> itemList,
ListView videoFileListView,List<String> videoFilePath,View controlView,Context context) {
super();
mListView = videoFileListView;
mVideoFilePath = videoFilePath;
mControlView = controlView;
mContext = context;
mInflater = LayoutInflater.from(context);
if (itemList != null) {
this.itemList = itemList;
} else {
this.itemList = new ArrayList<HashMap<String, Object>>();
}
if (selectid != null && selectid.size() != 0) {
selectid.clear();
}
mView = new HashMap<Integer, View>();
isCheck = new HashMap<Integer, Boolean>();
isMulChoice = true;
for (int i = 0; i < itemList.size(); i++) {
isCheck.put(i, false);
}
}
public void updateView(String path,Bitmap bitmap){
Log.d(TAG, "*** updateView();itemList.size is:"+itemList.size()
+";bitmap is:"+bitmap
+";path is:"+path);
if (selectid != null && selectid.size() != 0) {
selectid.clear();
}
for (int i = 0; i < itemList.size(); i++) {
isCheck.put(i, false);
}
if(bitmap != null){
ImageView mImageView = (ImageView) mListView.findViewWithTag(path);
if (mListView != null && mImageView != null) {
mImageView.setImageBitmap(bitmap);
}
}
notifyDataSetChanged();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return itemList.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
// return null;
return mVideoFilePath.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//全选操作
public void checkAll() {
for (int i = 0; i < itemList.size(); i++) {
isCheck.put(i, true);
}
notifyDataSetChanged();
}
public List<String> selectIdGet(){
return selectid;
}
public void selectIdAdd(String itemString){
selectid.add(itemString);
}
public void selectIdClear(){
selectid.clear();
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
// TODO Auto-generated method stub
Log.d(TAG, "*** getView()");
final ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.files_list, null);
viewHolder.file_lable = (MyImageView) convertView
.findViewById(R.id.file_lable);
viewHolder.file_check = (CheckBox) convertView
.findViewById(R.id.file_check_box);
viewHolder.fileName = (TextView) convertView
.findViewById(R.id.file_name);
viewHolder.fileSize = (TextView) convertView
.findViewById(R.id.file_size);
viewHolder.fileData = (TextView) convertView
.findViewById(R.id.file_data);
viewHolder.fileTime = (TextView) convertView
.findViewById(R.id.file_time);
viewHolder.file_lable
.setOnMeasureListener(new OnMeasureListener() {
public void onMeasureSize(int width, int height) {
// TODO Auto-generated method stub
mPoint.set(width, height);
}
});
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.fileName.setText((String) itemList.get(position)
.get(Global.mapFileName));
viewHolder.fileSize.setText((String) itemList.get(position)
.get(Global.mapFileSize));
viewHolder.fileData.setText((String) itemList.get(position)
.get(Global.mapFileData));
viewHolder.fileTime.setText((String) itemList.get(position)
.get(Global.mapFileTime));
convertView.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
// click the item and playVideo
String path = new String();
path = mVideoFilePath.get(position);
Uri videoPath = Uri.parse(path);
//播放视频
VideoUtil.getInstance(mContext).playVideo(videoPath);
}
});
String fileAbsolutePath = Global.defaule_storage_path + "/"
+ itemList.get(position).get(Global.mapFileName);
//the checkBox's Listener must before the init of checkBox
viewHolder.file_check.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox cb = (CheckBox) v;
if(cb.isChecked()){
mControlView.setVisibility(View.VISIBLE);
selectid.add(mVideoFilePath.get(position));
isCheck.put(position, true);
}else{
mControlView.setVisibility(View.GONE);
selectid.remove(mVideoFilePath.get(position));
isCheck.remove(position);
}
}
});
if (isCheck.get(position) != null) {
Log.d(TAG, "*** isCheck.get(position) is:"+isCheck.get(position));
viewHolder.file_check.setChecked(isCheck.get(position));
}
viewHolder.file_lable.setTag(fileAbsolutePath);
ifFileLock = itemList.get(position).get(Global.mapFileLock)
.toString();
Log.d(TAG, "** before NativeVideoThumbnailLoader(); ifFileLock is: "+ifFileLock);
//异步加载图片
Bitmap bitmap = NativeVideoThumbnailLoader.getInstance()
.loadNativeImage(fileAbsolutePath, mPoint, ifFileLock,
new NativeImageCallBack() {
@Override
public void onImageLoader(Bitmap bitmap,
String path) {
Log.d(TAG, "***Callback onImageLoader();path is:"+path
+";bitmap is:"+bitmap);
ImageView mImageView = (ImageView) mListView
.findViewWithTag(path);
if (bitmap != null && mImageView != null) {
mImageView.setImageBitmap(bitmap);
}
}
});
Log.e(TAG, "*** after NativeVideoThumbnailLoader: bitmap is:"+bitmap);
if (bitmap != null) {
viewHolder.file_lable.setImageBitmap(bitmap);
} else {
if (ifFileLock.equals(DataBaseUtil.dbFileLock)) {
viewHolder.file_lable
.setImageResource(R.drawable.file_video_lock);
} else {
viewHolder.file_lable
.setImageResource(R.drawable.file_video);
}
}
return convertView;
}
static class ViewHolder {
CheckBox file_check;
TextView fileName;
TextView fileSize;
TextView fileData;
TextView fileTime;
MyImageView file_lable;
}
}
关于adapter原理相关的知识点,相信网上是有一大堆,而且都是分析的很不错。附上个人觉得不错关于adapter深入理解和优化的链接:
点击打开链接 http://mobile.51cto.com/abased-445617.htm。
而我要说的点,是前面遇到的问题,也是为了给自己提个醒,下次写代码时,代码质量能得到提高:
1>使用ViewHolder ,这样刷新view的时候 就不用每次都去解析 布局的xml文件;
2>对checkBox的监听,需要放在对checkBox 的初始化之前;
3>对checkBox只需要设置onClick 监听,不需要设置Change监听,在onClick监听中可以通过下面方式直接判断checkBox的选中状态
viewHolder.file_check.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
CheckBox cb = (CheckBox) v;
if(cb.isChecked()){
mControlView.setVisibility(View.VISIBLE);
selectid.add(mVideoFilePath.get(position));
isCheck.put(position, true);
}else{
mControlView.setVisibility(View.GONE);
selectid.remove(mVideoFilePath.get(position));
isCheck.remove(position);
}
}
});
4>关于增大checkBox的点击区域,如果只是有一个checkBox的话,可以增大checkBox的背景区域,对checkBox的背景进行监听,通过设置一个全局变量,通过判断全局变量的变化,判断checkBox的选中状态;
如果是有多个checkBox的话,就需要设置 集合对相应的position的checkBox的状态进行记录,我做了如下的尝试: 定义的 public HashMap<Integer,Integer> checkBoxPos; 就是用来记录相应position的checkBox的选中状态,个人觉得思路是没有问题,不过测试的过程中,还是出现了checkBox的选中状态显示混乱的问题,不过通过log打印,实际的状态是没有错的,只是图标显示混乱,而我又找不大原因。所以最后干脆是直接在原来自定义checkBox的图片的基础上增大透明背景。
viewHolder.check_box__layout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
// CheckBox cb = (CheckBox) v;
Log.d(TAG, "*** position is:"+position
+";checkBoxPos.get(position) is:"+ checkBoxPos.get(position));
if(0 == checkBoxPos.get(position)){
checkBoxPos.put(position,1);
mControlView.setVisibility(View.VISIBLE);
selectid.add(mVideoFilePath.get(position));
isCheck.put(position, true);
viewHolder.file_check.setBackgroundResource(R.drawable.file_check_on);
}else{
checkBoxPos.put(position, 0);
mControlView.setVisibility(View.GONE);
selectid.remove(mVideoFilePath.get(position));
isCheck.remove(position);
viewHolder.file_check.setBackgroundResource(R.drawable.file_check_off);
}
}
});
本来是想写一些关于adapter的原理性的东西,奈何理解不够深入,也觉得别人写的的确很好了。在这里也只是想记录先自己遇到的问题以及解决的方法,相信只有想我这种菜鸟才会遇到这种问题吧。