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
17package com.android.videoeditor;
18
19import java.util.ArrayList;
20import java.util.HashSet;
21import java.util.List;
22import java.util.Set;
23
24import android.content.Context;
25import android.graphics.Bitmap;
26import android.graphics.drawable.BitmapDrawable;
27import android.os.AsyncTask;
28import android.view.View;
29import android.view.ViewGroup;
30import android.widget.AbsListView;
31import android.widget.BaseAdapter;
32import android.widget.ImageView;
33import android.widget.TextView;
34
35/**
36 * Base class for BaseAdapters which load images.
37 */
38public 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