通过print callstack得知gallery里面获得thumbnail 是通过LocalVideo.requestImage往下调用的:
com.android.gallery3d.data.LocalVideo.requestImage(LocalVideo.java:143)
com.android.gallery3d.ui.AlbumSlidingWindow$AlbumDisplayItem.startLoadBitmap(AlbumSlidingWindow.java:372)
com.android.gallery3d.ui.AbstractDisplayItem.requestImage(AbstractDisplayItem.java:81)
在LocalVideo.java里面直接调用return LocalVideoRequest对象:
所以简单的说thumbnail就是LocalVideoRequest得到的,细节就要往下看了。
@Override
public Job requestImage(int type) {
return new LocalVideoRequest(mApplication, getPath(), type, filePath);
}
-
LocalVideoRequest直接调用ImageCacheRequest的实现
-
LocalVideoRequest里面override了onDecodeOriginal方法
public static class LocalVideoRequest extends ImageCacheRequest { private String mLocalFilePath; LocalVideoRequest(GalleryApp application, Path path, int type, String localFilePath) { super(application, path, type, LocalImage.getTargetSize(type)); mLocalFilePath = localFilePath; } @Override public Bitmap onDecodeOriginal(JobContext jc, int type) { Bitmap bitmap = BitmapUtils.createVideoThumbnail(mLocalFilePath); if (bitmap == null || jc.isCancelled()) return null; return bitmap; } }
ImageCacheRequest:
1. 首先创建ImageCacheService对象[在ImageCacheRequest::run()]
ImageCacheService cacheService = mApplication.getImageCacheService();
2. 通过CacheService.getImageData获取ImageData
ImageData data = cacheService.getImageData(mPath, mType);
3. 如果data不为null,对data进行decode,然后return,
如果data为空就调用上面说到的onDecodeOriginal创建新的thumbnail
再把经过处理的bitmap写进文件里面(cacheService.putImageData)
if (data != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = DecodeUtils.requestDecode(jc, data.mData,
data.mOffset, data.mData.length - data.mOffset, options);
if (bitmap == null && !jc.isCancelled()) {
Log.w(TAG, "decode cached failed " + debugTag);
}
return bitmap;
} else {
Bitmap bitmap = onDecodeOriginal(jc, mType);
if (jc.isCancelled()) return null;
if (bitmap == null) {
Log.w(TAG, "decode orig failed " + debugTag);
return null;
}
if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
bitmap = BitmapUtils.resizeDownAndCropCenter(bitmap,
mTargetSize, true);
} else {
bitmap = BitmapUtils.resizeDownBySideLength(bitmap,
mTargetSize, true);
}
if (jc.isCancelled()) return null;
byte[] array = BitmapUtils.compressBitmap(bitmap);
if (jc.isCancelled()) return null;
cacheService.putImageData(mPath, mType, array);
return bitmap;
}
ImageCacheService的实现:
有一个private对象: private BlobCache mCache;
通过在BlobCache.java增加log,BlobCache的路径为:
/mnt/sdcard/Android/data/com.android.gallery3d/cache/imgcache
// Creates the cache. Three files will be created:
// path + ".idx", path + ".0", and path + ".1"
// The ".0" file and the ".1" file each stores data for a region. Each of
// them can grow to the size specified by maxBytes. The maxEntries parameter
// specifies the maximum number of entries each region can have. If the
// "reset" parameter is true, the cache will be cleared before use.
public BlobCache(String path, int maxEntries, int maxBytes, boolean reset)
throws IOException {
this(path, maxEntries, maxBytes, reset, 0);
}
public BlobCache(String path, int maxEntries, int maxBytes, boolean reset,
int version) throws IOException {
mIndexFile = new RandomAccessFile(path + ".idx", "rw");
mDataFile0 = new RandomAccessFile(path + ".0", "rw");
mDataFile1 = new RandomAccessFile(path + ".1", "rw");
mVersion = version;
Gallery的cache目录:
/mnt/sdcard/Android/data/com.android.gallery3d/cache/
imgcache.0
imgcache.1
imgcache.idx
BlobCache的描述(BlobCache.java):
// This is an on-disk cache which maps a 64-bits key to a byte array.
//
// It consists of three files: one index file and two data files. One of the
// data files is "active", and the other is "inactive". New entries are
// appended into the active region until it reaches the size limit. At that
// point the active file and the inactive file are swapped, and the new active
// file is truncated to empty (and the index for that file is also cleared).
// The index is a hash table with linear probing. When the load factor reaches
// 0.5, it does the same thing like when the size limit is reached.
//
// The index file format: (all numbers are stored in little-endian)
// [0] Magic number: 0xB3273030
// [4] MaxEntries: Max number of hash entries per region.
// [8] MaxBytes: Max number of data bytes per region (including header).
// [12] ActiveRegion: The active growing region: 0 or 1.
// [16] ActiveEntries: The number of hash entries used in the active region.
// [20] ActiveBytes: The number of data bytes used in the active region.
// [24] Version number.
// [28] Checksum of [0..28).
// [32] Hash entries for region 0. The size is X = (12 * MaxEntries bytes).
// [32 + X] Hash entries for region 1. The size is also X.
//
// Each hash entry is 12 bytes: 8 bytes key and 4 bytes offset into the data
// file. The offset is 0 when the slot is free. Note that 0 is a valid value
// for key. The keys are used directly as index into a hash table, so they
// should be suitably distributed.
//
// Each data file stores data for one region. The data file is concatenated
// blobs followed by the magic number 0xBD248510.
//
// The blob format:
// [0] Key of this blob
// [8] Checksum of this blob
// [12] Offset of this blob
// [16] Length of this blob (not including header)
// [20] Blob
//
// Below are the interface for BlobCache. The instance of this class does not
// support concurrent use by multiple threads.
//
// public BlobCache(String path, int maxEntries, int maxBytes, boolean reset) throws IOException;
// public void insert(long key, byte[] data) throws IOException;
// public byte[] lookup(long key) throws IOException;
// public void lookup(LookupRequest req) throws IOException;
// public void close();
// public void syncIndex();
// public void syncAll();
// public static void deleteFiles(String path);