1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.videoeditor; 18 19 import java.util.ArrayList; 20 import java.util.HashSet; 21 import java.util.List; 22 import java.util.Set; 23 24 import android.content.Context; 25 import android.graphics.Bitmap; 26 import android.graphics.drawable.BitmapDrawable; 27 import android.os.AsyncTask; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.widget.AbsListView; 31 import android.widget.BaseAdapter; 32 import android.widget.ImageView; 33 import android.widget.TextView; 34 35 /** 36 * Base class for BaseAdapters which load images. 37 */ 38 public abstract class BaseAdapterWithImages<K> extends BaseAdapter { 39 protected final Context mContext; 40 private final List<ImageViewHolder<K>> mViewHolders; 41 // For recording keys of images that are being loaded 42 private final Set<K> mLoadingImages; 43 private final AbsListView mListView; 44 45 /** 46 * View holder class 47 */ 48 protected static class ImageViewHolder<K> { 49 private final ImageView mImageView; 50 private K mKey; 51 52 public ImageViewHolder(View rowView) { 53 mImageView = (ImageView) rowView.findViewById(R.id.item_preview); 54 } 55 56 public void setKey(K key) { 57 mKey = key; 58 } 59 } 60 61 /** 62 * View holder class 63 */ 64 protected static class ImageTextViewHolder<K> extends ImageViewHolder<K> { 65 protected final TextView mNameView; 66 67 public ImageTextViewHolder(View rowView) { 68 super(rowView); 69 mNameView = (TextView) rowView.findViewById(R.id.item_name); 70 } 71 } 72 73 /** 74 * Image loader class 75 */ 76 protected class ImageLoaderAsyncTask extends AsyncTask<Void, Void, Bitmap> { 77 private final K mKey; 78 private final Object mData; 79 80 /** 81 * Constructor 82 * 83 * @param key The bitmap key 84 * @param data The data 85 */ 86 public ImageLoaderAsyncTask(K key, Object data) { 87 mKey = key; 88 mData = data; 89 } 90 91 @Override 92 protected Bitmap doInBackground(Void... zzz) { 93 return loadImage(mData); 94 } 95 96 @Override 97 protected void onPostExecute(Bitmap bitmap) { 98 mLoadingImages.remove(mKey); 99 if (bitmap == null) { 100 return; 101 } 102 103 for (ImageViewHolder<K> viewHolder : mViewHolders) { 104 if (mKey.equals(viewHolder.mKey)) { 105 viewHolder.mImageView.setImageBitmap(bitmap); 106 return; 107 } 108 } 109 110 bitmap.recycle(); 111 } 112 } 113 114 /** 115 * Constructor 116 * 117 * @param context The context 118 * @param listView The list view 119 */ 120 public BaseAdapterWithImages(Context context, AbsListView listView) { 121 mContext = context; 122 mListView = listView; 123 mLoadingImages = new HashSet<K>(); 124 mViewHolders = new ArrayList<ImageViewHolder<K>>(); 125 126 mListView.setRecyclerListener(new AbsListView.RecyclerListener() { 127 @Override 128 @SuppressWarnings("unchecked") 129 public void onMovedToScrapHeap(View view) { 130 final ImageViewHolder<K> viewHolder = (ImageViewHolder<K>)view.getTag(); 131 132 mViewHolders.remove(viewHolder); 133 viewHolder.setKey(null); 134 135 final BitmapDrawable drawable 136 = (BitmapDrawable)viewHolder.mImageView.getDrawable(); 137 if (drawable != null && drawable.getBitmap() != null) { 138 viewHolder.mImageView.setImageDrawable(null); 139 drawable.getBitmap().recycle(); 140 } 141 } 142 }); 143 } 144 145 public void onPause() { 146 mViewHolders.clear(); 147 } 148 149 /** 150 * Upon destroy, recycle all images and then remove all child views in the list view. 151 */ 152 public void onDestroy() { 153 final int count = mListView.getChildCount(); 154 for (int i = 0; i < count; i++) { 155 final View rowView = mListView.getChildAt(i); 156 final ImageView imageView = (ImageView)rowView.findViewById(R.id.item_preview); 157 final BitmapDrawable drawable = (BitmapDrawable)imageView.getDrawable(); 158 if (drawable != null && drawable.getBitmap() != null) { 159 drawable.getBitmap().recycle(); 160 } 161 } 162 163 mListView.removeViews(0, count); 164 System.gc(); 165 } 166 167 /** 168 * Starts the AsyncTask which loads the bitmap. 169 * 170 * @param key The bitmap key 171 * @param data The data 172 * @param viewHolder The view holder 173 */ 174 protected void initiateLoad(K key, Object data, ImageViewHolder<K> viewHolder) { 175 // The adapter may recycle a view and then reuse it. 176 if (!mViewHolders.contains(viewHolder)) { 177 mViewHolders.add(viewHolder); 178 } 179 viewHolder.setKey(key); 180 181 if (!mLoadingImages.contains(key)) { 182 mLoadingImages.add(key); 183 new ImageLoaderAsyncTask(key, data).execute(); 184 } 185 } 186 187 @Override 188 public long getItemId(int position) { 189 return position; 190 } 191 192 @Override 193 public abstract int getCount(); 194 195 @Override 196 public abstract Object getItem(int position); 197 198 @Override 199 public abstract View getView(int position, View convertView, ViewGroup parent); 200 201 /** 202 * Loads an image based on its key. 203 * 204 * @param data The data required to load the image 205 * 206 * @return The loaded bitmap 207 */ 208 protected abstract Bitmap loadImage(Object data); 209 } 210