最近在使用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的原理性的東西,奈何理解不夠深入,也覺得別人寫的的確很好了。在這裏也只是想記錄先自己遇到的問題以及解決的方法,相信只有想我這種菜鳥纔會遇到這種問題吧。