您的位置:首页 > 移动开发 > Android开发

对一个gridview异步加载大量图片的实例的个人理解

2015-01-07 17:51 357 查看
首先贴上原代码地址:链接

然后是在自己代码中的运用

public class GridAdapter extends BaseAdapter {
private MediaThumbnail mtb;
private final static String TAG="GridAdapter";
private LayoutInflater mInflater;
private ArrayList<BaseData> gridOnePage = new ArrayList<BaseData>();
private Resources resourceGrid;
private static int thumbnailVideoOrMusic=-100;
public GridAdapter(Context context,ArrayList<BaseData>gridOnePage) {
this.mInflater = LayoutInflater.from(context);
this.gridOnePage=gridOnePage;
}

public int getCount() {
//return mData.size();
if(gridOnePage==null)
return 0;
return gridOnePage.size();
}

public Object getItem(int arg0) {
return null;
}

public long getItemId(int arg0) {
return 0;
}

public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.gridview_item, null);
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.title = (TextView) convertView.findViewById(R.id.title);
//holder.info = (TextView) convertView.findViewById(R.id.info);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(gridOnePage.get(position).getType() == Constants.FILE_TYPE_VIDEO){
Drawable drawable =null;
drawable = FileBrowserActivity.fileTypeDrawable.get(3);
holder.img.setImageDrawable(drawable);
}

else{
Drawable drawable =null;
if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_FILE){

drawable = FileBrowserActivity.fileTypeDrawable.get(0);
holder.img.setImageDrawable(drawable);
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_PICTURE){

drawable = FileBrowserActivity.fileTypeDrawable.get(1);
holder.img.setImageDrawable(drawable);
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_SONG){

drawable = FileBrowserActivity.fileTypeDrawable.get(2);
holder.img.setImageDrawable(drawable);
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_DIR){

drawable = FileBrowserActivity.fileTypeDrawable.get(4);
holder.img.setImageDrawable(drawable);
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_RETURN){

drawable = FileBrowserActivity.fileTypeDrawable.get(5);
holder.img.setImageDrawable(drawable);
}
}

holder.title.setText((String) gridOnePage.get(position).getName());
if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_VIDEO){

String url =gridOnePage.get(position).getPath();
if (cancelPotentialLoad(url, holder.img)) {
try{
AsyncLoadImageTask task = new AsyncLoadImageTask(holder.img,0);
LoadedDrawable loadedDrawable = new LoadedDrawable(task);
holder.img.setImageDrawable(loadedDrawable);
task.execute(position);
}catch(Exception e){

}

}

}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_SONG){
String url =gridOnePage.get(position).getPath();
if (cancelPotentialLoad(url, holder.img)) {

try{
AsyncLoadImageTask task = new AsyncLoadImageTask(holder.img,1);
LoadedDrawable loadedDrawable = new LoadedDrawable(task);
holder.img.setImageDrawable(loadedDrawable);
task.execute(position);
}catch(Exception e){

}
}

}

return convertView;
}
public final class ViewHolder {
public ImageView img;
public TextView title;
//public TextView info;
}
private Bitmap getBitmapFromUrl(String url,int fileType){

Bitmap bitmap = null;
mtb= new MediaThumbnail();
File file = new File(url);
if(0==fileType)
bitmap = mtb.createVideoThumbnail(file.getAbsolutePath());
else if(1==fileType)
bitmap = mtb.createAlbumThumbnail(file.getAbsolutePath());
bitmap=ThumbnailUtils.extractThumbnail(bitmap, 151, 159);
//Drawable drawable=new BitmapDrawable(bitmap);
return bitmap;
}

//加载图片的异步任务
private class AsyncLoadImageTask extends AsyncTask<Integer, Void, Bitmap>{
private String url = null;
private final WeakReference<ImageView> imageViewReference;
private int fileType;

public AsyncLoadImageTask(ImageView imageview,int fileType) {
super();
// TODO Auto-generated constructor stub
imageViewReference = new WeakReference<ImageView>(imageview);
this.fileType=fileType;
}

@Override
protected Bitmap doInBackground(Integer... params) {//task.execute(position);来的参数
// TODO Auto-generated method stub
Bitmap bitmap = null;
//this.url = mList.get(params[0]);
if(params[0]>=gridOnePage.size()){
this.cancel(true);
}
else{
this.url = gridOnePage.get(params[0]).getPath();
bitmap = getBitmapFromUrl(url,this.fileType);
}

//MainActivity.gridviewBitmapCaches.put(mList.get(params[0]), bitmap);
return bitmap;
}
/*
在构造函数中建立的一个task->imageview的引用
*/
@Override
protected void onPostExecute(Bitmap resultBitmap) {
// TODO Auto-generated method stub
if(isCancelled()){
resultBitmap = null;
}
if(imageViewReference != null){
ImageView imageview = imageViewReference.get();
AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);
// Change bitmap only if this process is still associated with it
if (this == loadImageTask) {
imageview.setImageBitmap(resultBitmap);
imageview.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
}
}
super.onPostExecute(resultBitmap);
}
}

private boolean cancelPotentialLoad(String url,ImageView imageview){
AsyncLoadImageTask loadImageTask = getAsyncLoadImageTask(imageview);

if (loadImageTask != null) {
String bitmapUrl = loadImageTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
loadImageTask.cancel(true);
} else {
// 相同的url已经在加载中.
return false;
}
}
return true;

}

//当 loadImageTask.cancel(true)被执行的时候,则AsyncLoadImageTask 就会被取消,
//当AsyncLoadImageTask 任务执行到onPostExecute的时候,如果这个任务加载到了图片,
//它也会把这个bitmap设为null了。
//getAsyncLoadImageTask代码如下:
private AsyncLoadImageTask getAsyncLoadImageTask(ImageView imageview){
if (imageview != null) {

Drawable drawable = imageview.getDrawable();
if (drawable instanceof LoadedDrawable) {

LoadedDrawable loadedDrawable = (LoadedDrawable)drawable;
return loadedDrawable.getLoadImageTask();
}
}
return null;
}

//该类功能为:记录imageview加载任务并且为imageview设置默认的drawable
public static class LoadedDrawable extends ColorDrawable{
private final WeakReference<AsyncLoadImageTask> loadImageTaskReference;

public LoadedDrawable(AsyncLoadImageTask loadImageTask) {
super(Color.TRANSPARENT);
loadImageTaskReference =
new WeakReference<AsyncLoadImageTask>(loadImageTask);
}

public AsyncLoadImageTask getLoadImageTask() {
return loadImageTaskReference.get();
}

}

下面是我的理解:

在某任务已经执行

在task类中含有对imageview的弱引用,也就是说当判断一个taskA有没有过时,那么

利用弱引用求出该taskA对应的imageview,然后再用imageview求出其对应的当前的taskB,

如果tashA,taskB不对等的话,则会取消taskA,因为taskB才是该Imageview最新的task。

getAsyncLoadImageTask就是通过该Imageview的Drawable属于LoadedDrawable类的实例,也就是对象,是的话

则获取其对应的弱引用:task。

上面这一句话不是很理解:但我认为是holder.img.setImageDrawable(loadedDrawable);之后的结果。

cancelPotentialLoad:

在准备执行某个Imageview的任务的时候,如果该Imageview的url已经在加载,那么就不必再加载了。

在什么时候会出现这样的情况呢?在一个不断上下滑动,或者不断上下翻页的情况出现。比如1212121212(页数)

onpostexcute的if(imageViewReference != null):

就是在执行完毕的时候,对于某个Imageview,选择哪一个task的结果来显示。

在什么时候会出现这样的情况呢?在一个ImageView的可能会先显示上一个task的结果,然后再显示当前task的结果。

显然这不是我们想要的结果,直接显示当前task的结果是我们期望的结果。

有同学说cancelPotentialLoad里面if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
       
loadImageTask.cancel(true);        
       }

不是已经杜绝了这种情况么?我现在只能理解在复杂的多线程中进一步检查一遍

另外因为上面的代码对于我来说还差点实用性,也有点难理解,不好维护,主要是最后一个函数

所以我自己写了一个

public class GridAdapter extends BaseAdapter {
private MediaThumbnail mtb;
private final static String TAG="GridAdapter";
private LayoutInflater mInflater;
private ArrayList<BaseData> gridOnePage = new ArrayList<BaseData>();
private Resources resourceGrid;
private static int thumbnailVideoOrMusic=-100;
//ArrayList<AsyncLoadImageTask> imagePosition2Task = new ArrayList<AsyncLoadImageTask>();
public static AsyncLoadImageTask imagePosition2Task[] = new AsyncLoadImageTask[24+1];
public static int isFinish[] =new int[24+1];
public static ImageView ivHasCancelTask[]=new ImageView[24+1];
public GridAdapter(Context context,ArrayList<BaseData>gridOnePage) {
this.mInflater = LayoutInflater.from(context);
this.gridOnePage=gridOnePage;
}
public GridAdapter(){}
public int getCount() {
//return mData.size();
if(gridOnePage==null)
return 0;
return gridOnePage.size();
}

public Object getItem(int arg0) {
return null;
}

public long getItemId(int arg0) {
return 0;
}

public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.gridview_item, null);
holder.img = (ImageView) convertView.findViewById(R.id.img);
holder.title = (TextView) convertView.findViewById(R.id.title);
//holder.info = (TextView) convertView.findViewById(R.id.info);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(gridOnePage.get(position).getType() == Constants.FILE_TYPE_VIDEO){
Drawable drawable =null;
drawable = FileBrowserActivity.fileTypeDrawable.get(3);
holder.img.setImageDrawable(drawable);
isFinish[position]=-1;
}

else{
Drawable drawable =null;
if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_FILE){
imagePosition2Task[position]=null;
drawable = FileBrowserActivity.fileTypeDrawable.get(0);
holder.img.setImageDrawable(drawable);
isFinish[position]=1;
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_PICTURE){
imagePosition2Task[position]=null;
drawable = FileBrowserActivity.fileTypeDrawable.get(1);
holder.img.setImageDrawable(drawable);
isFinish[position]=1;
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_SONG){

drawable = FileBrowserActivity.fileTypeDrawable.get(2);
holder.img.setImageDrawable(drawable);
isFinish[position]=1;
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_DIR){
imagePosition2Task[position]=null;
drawable = FileBrowserActivity.fileTypeDrawable.get(4);
holder.img.setImageDrawable(drawable);
isFinish[position]=1;
}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_RETURN){
imagePosition2Task[position]=null;
drawable = FileBrowserActivity.fileTypeDrawable.get(5);
holder.img.setImageDrawable(drawable);
isFinish[position]=1;
}
}

holder.title.setText((String) gridOnePage.get(position).getName());
if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_VIDEO){
String url =gridOnePage.get(position).getPath();
if(cancelPotentialLoad(url, position)){
try{
AsyncLoadImageTask task = new AsyncLoadImageTask(holder.img,0);
imagePosition2Task[position]=task;
ivHasCancelTask[position]=holder.img;
task.execute(position);
}
catch (Exception e) {   Log.e("error", e.toString());}
}

}
else if(gridOnePage.get(position).getType()==Constants.FILE_TYPE_SONG){
String url =gridOnePage.get(position).getPath();
if(cancelPotentialLoad(url, position)){
try{
AsyncLoadImageTask task = new AsyncLoadImageTask(holder.img,1);
imagePosition2Task[position]=task;
task.execute(position);
}catch(Exception e) {   Log.e("error", e.toString());  }

}
}
return convertView;
}

public AsyncLoadImageTask createTaskObject(ImageView imageview,int fileType){
AsyncLoadImageTask task = new AsyncLoadImageTask(imageview,fileType);
return task;
}
public final class ViewHolder {
public ImageView img;
public TextView title;
//public TextView info;
}
private Drawable getBitmapFromUrl(String url,int filetype){

Bitmap bitmap = null;
mtb= new MediaThumbnail();
File file = new File(url);
//Log.i(TAG, "-------getBitmapFromUrl------thumbnailVideoOrMusic:"+String.valueOf(thumbnailVideoOrMusic)+
//"------fileUrl-------:"+file.getAbsolutePath());
if(0==filetype){
bitmap = mtb.createVideoThumbnail(file.getAbsolutePath());
}

else if(1==filetype){
bitmap = mtb.createAlbumThumbnail(file.getAbsolutePath());
}

bitmap=ThumbnailUtils.extractThumbnail(bitmap, 380, 380);
if(bitmap == null){
//Log.i(TAG,"----ThumbnailUtils.extractThumbnail-bitmap--NULL");
}
else{
//Log.i(TAG,"----ThumbnailUtils.extractThumbnail-bitmap-NOT-NULL");
}
if(bitmap == null) return null;
Drawable drawable=new BitmapDrawable(bitmap);
//return bitmap;
return drawable;
}

public class AsyncLoadImageTask extends AsyncTask<Integer, Void, Drawable>{
private String url = null;
private final WeakReference<ImageView> imageViewReference;
private ImageView iv;
private int taskPos;
private int fileType;//video is 0 and music is 1
public AsyncLoadImageTask(ImageView imageview,int fileType) {
super();
// TODO Auto-generated constructor stub
this.iv=imageview;
this.fileType=fileType;
imageViewReference = new WeakReference<ImageView>(imageview);

}

@Override
protected Drawable doInBackground(Integer... params) {//task.execute(position);来的参数
Log.i(TAG, "-------doInBackground");
// TODO Auto-generated method stub
Drawable drawable = null;
if(params[0]>=gridOnePage.size()){
//Log.i(TAG,"--doInBackground--params[0]--gridOnePage.size()"+
//String.valueOf(params[0])+"--"+String.valueOf(gridOnePage.size()));
this.cancel(true);
}else{
//Log.i(TAG, "-------params[0]<gridOnePage.size()----");
this.taskPos =	params[0];
this.url = gridOnePage.get(params[0]).getPath();
drawable = getBitmapFromUrl(this.url,this.fileType);

}

return drawable;
}
@Override
protected void onPostExecute(Drawable resultDrawable) {
//Log.i(TAG,"------onPostExecute---this.taskPos---"+String.valueOf(this.taskPos));

if(isCancelled())resultDrawable = null;
if(imageViewReference != null){
ImageView imageview = imageViewReference.get();
AsyncLoadImageTask loadImageTask =imagePosition2Task[this.taskPos] ;
if(loadImageTask==null){
//Log.i(TAG,"---loadImageTask==null---");
}else{
//Log.i(TAG,"---loadImageTask---not null----loadImageTask.url--"+loadImageTask.url);
}
if (this == loadImageTask && resultDrawable!=null) {
//Log.i(TAG,"------draw the image---this.taskPos---"+String.valueOf(this.taskPos));
iv.setImageDrawable(resultDrawable);

}
}
/*
if(resultDrawable==null){
Log.i(TAG, "#######000-------onPostExecute---positionDebug:"+String.valueOf(positionDebug));
}
else{
Log.i(TAG, "#######111-------onPostExecute---positionDebug:"+String.valueOf(positionDebug));
iv.setImageDrawable(resultDrawable);
}*/
isFinish[this.taskPos]=1;

super.onPostExecute(resultDrawable);
}

protected void onPreExecute () {
//Log.i(TAG, "-------onPreExecute");
}
}
private boolean cancelPotentialLoad(String url,int position){
AsyncLoadImageTask loadImageTask = imagePosition2Task[position];

if (loadImageTask != null) {
String bitmapUrl = loadImageTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
loadImageTask.cancel(true);
} else {
// 相同的url已经在加载中.
return false;
}
}
return true;

}

}


小结:其实对于弱引用,我在这里没必要用,因为我做的是gridview分页,所以不会轻易出现out of memory的问题(一页显示12个),另外对于asynctask中的弱引用我保留了但是丢弃了LoadedDrawable类,因为这只是一个记录的作用。所以我用了数组来模拟,简单粗暴,暂时没发现什么问题。

<span style="font-family:Comic Sans MS;">imagePosition2Task[position];</span>
在这个数组中,我用每个Imageview的pisition来记录每个Imageview,装的是其最新的task对象。

asynctask中的弱引用保留时因为要找到正在运行的task对应的Imageview,所以上面代码实现了两边互相映射

我也建立了互相映射。

PS:如有侵权,联系我删掉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息