通过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<Bitmap> 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);