0. 原文拜读
- 作者:lb377463323
- 出处:http://blog.csdn.net/lb377463323
- 原文链接:http://blog.csdn.net/lb377463323/article/details/70890461
1. AlbumSetPage界面数据装载和界面刷新,为加载专辑缩略图准备
1. 数据装载
package com.android.gallery3d.app;
public class AlbumSetPage extends ActivityState implements OnClickListener,...{
private AlbumSetDataLoader mAlbumSetDataAdapter;
@Override
public void onResume() {
super.onResume();
...
mAlbumSetDataAdapter.resume();
...
}
}
- 上接mAlbumSetDataAdapter.resume()
package com.android.gallery3d.app;
public class AlbumSetDataLoader {
public void resume() {
mSource.addContentListener(mSourceListener);
mReloadTask = new ReloadTask();
mReloadTask.start();
}
- 上接 ReloadTask()
// TODO: load active range first
private class ReloadTask extends Thread {
@Override
public void run() {
while (mActive) {
...
// 数据加载完成,进入界面刷新
executeAndWait(new UpdateContent(info));
}
}
}
1.2 界面刷新的回调事件
- 上接 executeAndWait(new UpdateContent(info));
private class UpdateContent implements Callable<Void> {
private final UpdateInfo mUpdateInfo;
@Override
public Void call() {
...
for (DataListener l : mDataListener) {
l.onSizeChanged(mSize);
}
...
for (DataListener l : mDataListener) {
l.onContentChanged(info.index);
}
}
}
- 查看下接口定义
package com.android.gallery3d.app;
public static interface DataListener {
public void onContentChanged(int index);
public void onSizeChanged(int size);
}
- grep命令查看实现该接口
目前只有 AlbumSetSlidingWindow 实现
src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java:40:public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
具体如下
package com.android.gallery3d.ui;
public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
@Override
public void onContentChanged(int index) {
....
//mData是容量为96的AlbumSetEntry数组,index是代表加载哪一个专辑,范围是0-(n-1),n为专辑数
AlbumSetEntry entry = mData[index % mData.length];
//专辑缩略图和label主要由下面三个方法完成
updateAlbumSetEntry(entry, index);
updateAllImageRequests();
updateTextureUploadQueue();
//onContentChanged方法就是执行mSlotView.invalidate()刷新界面
if (mListener != null && isActiveSlot(index)) {
mListener.onContentChanged();
}
}
2. 加载专辑缩略图
package com.android.gallery3d.ui;
public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
@Override
public void onContentChanged(int index) {
....
//mData是容量为96的AlbumSetEntry数组,index是代表加载哪一个专辑,范围是0-(n-1),n为专辑数
AlbumSetEntry entry = mData[index % mData.length];
//专辑缩略图和label主要由下面三个方法完成
updateAlbumSetEntry(entry, index);
updateAllImageRequests();
updateTextureUploadQueue();
...
}
2.1 AlbumSetSlidingWindow.updateAlbumSetEntry
缩略图和标签的准备
private void updateAlbumSetEntry(AlbumSetEntry entry, int slotIndex) {
...
//cover: 从专辑里面获取的一个图片,用来作为专辑缩略图
MediaItem cover = mSource.getCoverItem(slotIndex);
...
entry.coverItem = cover;
if (getDataVersion(cover) != entry.coverDataVersion) {
...
if (cover != null) {
//AlbumLabelLoader就是用来加载缩略图下面的label,如专辑名、此专辑有多少张图片等
entry.coverLoader = new AlbumCoverLoader(slotIndex, cover);
}
}
}
上接 new AlbumCoverLoader(slotIndex, cover);
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
public AlbumCoverLoader(int slotIndex, MediaItem item) {
mSlotIndex = slotIndex;
mMediaItem = item;
}
}
上述便于 AlbumSetSlidingWindow.updateAllImageRequests 中 startLoadBitmap 的调用
2.2 AlbumSetSlidingWindow.updateAllImageRequests
加载缩略图和标签
private void updateAllImageRequests() {
mActiveRequestCount = 0;
for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
AlbumSetEntry entry = mData[i % mData.length];
// 开始执行缩略图和标签加载
if (startLoadBitmap(entry.coverLoader)) ++mActiveRequestCount;
if (startLoadBitmap(entry.labelLoader)) ++mActiveRequestCount;
}
...
}
上接 startLoadBitmap
private static boolean startLoadBitmap(BitmapLoader loader) {
if (loader == null) return false;
loader.startLoad();
return loader.isRequestInProgress();
}
上接 loader.startLoad
package com.android.gallery3d.ui;
// We use this class to
// 1.) load bitmaps in background.
// 2.) as a place holder for the loaded bitmap
public abstract class BitmapLoader implements FutureListener<Bitmap> {
public synchronized void startLoad() {
if (mState == STATE_INIT) {
mState = STATE_REQUESTED;
if (mTask == null) mTask = submitBitmapTask(this);
}
}
abstract protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l);
}
根据多态,这里的 loader 实现在 AlbumCoverLoader 和 AlbumLabelLoader
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
...
@Override
protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
//mMediaItem为LocalImage或LocalVideo,线程池
return mThreadPool.submit(mMediaItem.requestImage(
MediaItem.TYPE_MICROTHUMBNAIL), l);
}
...
}
public AlbumLabelLoader(
int slotIndex, String title, int totalCount, int totalImageCount,
int totalVideoCount,int albumCount, int sourceType) {
...
@Override
protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
// 标签
return mThreadPool.submit(mLabelMaker.requestLabel(
mTitle, String.valueOf(mTotalCount),mTotalImageCount,
mTotalVideoCount, mAlbumCount, mSourceType), l);
}
...
}
2.2.1 MediaItem.requestImage
- 上接 mMediaItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL)
package com.android.gallery3d.data;
// MediaItem represents an image or a video item.
public abstract class MediaItem extends MediaObject {
public abstract Job<Bitmap> requestImage(int type);
}
查看多态发现 LocalImage 实现了上述的 requestImage
package com.android.gallery3d.data;
// LocalMediaItem is an abstract class captures those common fields
// in LocalImage and LocalVideo.
//
public abstract class LocalMediaItem extends MediaItem {
}
// LocalImage represents an image in the local storage.
public class LocalImage extends LocalMediaItem {
@Override
public Job<Bitmap> requestImage(int type) {
// 返回加载Bitmap的Job工作任务,也就是ImageCacheRequest类
return new LocalImageRequest(mApplication, mPath, dateModifiedInSec,
type, filePath, mimeType);
}
}
- 上接
public static class LocalImageRequest extends ImageCacheRequest {
LocalImageRequest(GalleryApp application, Path path, long timeModified,
int type, String localFilePath, String mimeType) {
super(application, path, timeModified, type,
MediaItem.getTargetSize(type), localFilePath, mimeType);
mLocalFilePath = localFilePath;
}
2.2.2 ThreadPool.submit 线程池
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
...
@Override
protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
//mMediaItem为LocalImage或LocalVideo,线程池
return mThreadPool.submit(mMediaItem.requestImage(
MediaItem.TYPE_MICROTHUMBNAIL), l);
}
...
}
-
- ThreadPool.submit
package com.android.gallery3d.util;
public class ThreadPool {
private final Executor mExecutor;
public ThreadPool(int initPoolSize, int maxPoolSize) {
mExecutor = new ThreadPoolExecutor(
initPoolSize, maxPoolSize, KEEP_ALIVE_TIME,
TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
new PriorityThreadFactory("thread-pool",
android.os.Process.THREAD_PRIORITY_BACKGROUND));
}
// Submit a job to the thread pool. The listener will be called when the
// job is finished (or cancelled).
public <T> Future<T> submit(Job<T> job, FutureListener<T> listener) {
Worker<T> w = new Worker<T>(job, listener);
mExecutor.execute(w);
return w;
}
}
-
- ThreadPool.run
package com.android.gallery3d.util;
public class ThreadPool {
private class Worker<T> implements Runnable, Future<T>, JobContext {
// This is called by a thread in the thread pool.
@Override
public void run() {
...
// 完成缩略图加载任务后,回调到 AlbumCoverLoader 本身
if (mListener != null) mListener.onFutureDone(this);
}
}
- 查看AlbumCoverLoader没有onFutureDone回调方法,发现存在和BitmapLoader的继承关系,即onFutureDone在BitmapLoader回调
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
-
- BitmapLoader.onFutureDone
package com.android.gallery3d.ui;
public abstract class BitmapLoader implements FutureListener<Bitmap> {
@Override
public void onFutureDone(Future<Bitmap> future) {
...
synchronized (this) {
...
// 缩略图
mBitmap = future.get();
...
}
// 完成缩略图
onLoadComplete(mBitmap);
}
}
-
- BitmapLoader.onLoadComplete
abstract protected void onLoadComplete(Bitmap bitmap);
-
- AlbumSetSlidingWindow.AlbumCoverLoader.onLoadComplete
package com.android.gallery3d.ui;
public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
...
@Override
protected void onLoadComplete(Bitmap bitmap) {
mHandler.obtainMessage(MSG_UPDATE_ALBUM_ENTRY, this).sendToTarget();
}
...
}
public AlbumSetSlidingWindow(AbstractGalleryActivity activity,
AlbumSetDataLoader source, AlbumSetSlotRenderer.LabelSpec labelSpec,
SlotView.Spec slotSpec, int cacheSize) {
mHandler = new SynchronizedHandler(activity.getGLRoot()) {
@Override
public void handleMessage(Message message) {
Utils.assertTrue(message.what == MSG_UPDATE_ALBUM_ENTRY);
((EntryUpdater) message.obj).updateEntry();
}
};
}
private static interface EntryUpdater {
public void updateEntry();
}
-
- 回调事件 AlbumSetSlidingWindow.AlbumCoverLoader.updateEntry
package com.android.gallery3d.ui;
public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener {
// 回调事件
private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater {
@Override
public void updateEntry() {
// 获取缩略图
Bitmap bitmap = getBitmap();
if (bitmap == null) return; // error or recycled
AlbumSetEntry entry = mData[mSlotIndex % mData.length];
TiledTexture texture = new TiledTexture(bitmap);
entry.bitmapTexture = texture;
entry.content = texture;
if (isActiveSlot(mSlotIndex)) {
mContentUploader.addTexture(texture);
--mActiveRequestCount;
if (mActiveRequestCount == 0) requestNonactiveImages();
// packages/apps/Gallery/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java:234: private class MyCacheListener implements AlbumSetSlidingWindow.Listener {
if (mListener != null) mListener.onContentChanged();
} else {
mContentUploader.addTexture(texture);
}
}
}
上述的 getBitmap() 方法
package com.android.gallery3d.ui;
public abstract class BitmapLoader implements FutureListener<Bitmap> {
@Override
public void onFutureDone(Future<Bitmap> future) {
...
mBitmap = future.get();
...
}
public synchronized Bitmap getBitmap() {
return mBitmap;
}
根据上述代码可知,缩略图加载是通过线程池来完成的。至于此处线程池的原理,submit之后会在线程池中执行任务加载缩略图,从ThreadPool的run()方法中知道完成缩略图加载任务后,会调用mListener.onFutureDone(this),这里mListener就是BitmapLoader自身,从future.get中得到Bitmap传给onLoadComplete(mBitmap)。 之后发送Handler消息MSG_UPDATE_ALBUM_ENTRY调用AlbumCoverLoader的updateEntry()。
-
- mListener.onContentChanged
package com.android.gallery3d.ui;
public class AlbumSetSlotRenderer extends AbstractSlotRenderer {
private class MyCacheListener implements AlbumSetSlidingWindow.Listener {
@Override
public void onSizeChanged(int size) {
mSlotView.setSlotCount(size);
}
@Override
public void onContentChanged() {
mSlotView.invalidate();
}
}
-
- SlotView 的 render 方法, 完成界面的渲染
package com.android.gallery3d.ui;
public class SlotView extends GLView {
@Override
protected void render(GLCanvas canvas) {
super.render(canvas);
...
int r = renderItem(canvas,
requestedSlot[i], pass, paperActive);
...
}
}