博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Apollo播放器】源码分析之图片加载模式
阅读量:7225 次
发布时间:2019-06-29

本文共 19094 字,大约阅读时间需要 63 分钟。

hot3.png

图片加载有很多,部份都是使用LruCache、弱引用、软引用等编写的,其编目的就是优化内存、缓存、加载效果,不过,它们都是各有千秋,下面看看【Apollo播放器】它是对图片加载如何做的

它主要结构如下:

ImageInfo          - 图片信息相关

ImageCache       - 图片缓存相关

ImageProvider    -图片提供者相关(管理器)

GetBitmapTask   -图片下载任务

 下面一一分析每个类的结构和使用

ImageInfo.java

public class ImageInfo {		//图像类型	//专辑(ablum), 艺术家(artist), 播放列表(playlist), 流派genre	public String type;		//图像来源	//lastfm - 来自网站	//file - 来自音频	//gallery - 来自相册	//first_avail - 来自 'file' 或 'lastfm'	public String source;		//请求的图像的大小	//缩略图  or 正常图	public String size;		//执行图像获取所需的额外数据	//lastFM -    艺术家需要艺术家的形象	//ablum  -    专辑、歌手专辑图像	//file 	-     需要相册id	//gallery -   需要图像的文件路径	//first_available - 需要两个文件lastfm数据			public String[] data;	}

ImageCache.java

public final class ImageCache {    private static final String TAG = ImageCache.class.getSimpleName();    //二级缓存实例对象,其底层是继承自LinkedHashMap
    //具体实现请看源码:http://androidxref.com/4.4.2_r1/xref/packages/apps/UnifiedEmail/src/com/android/mail/utils/LruCache.java    private LruCache
 mLruCache;    private static ImageCache sInstance;    public ImageCache(final Context context) {        init(context);    }    /**     * 图片缓存单例模式     * @param context     * @return     */    public final static ImageCache getInstance(final Context context) {        if (sInstance == null) {            sInstance = new ImageCache(context.getApplicationContext());        }        return sInstance;    }    public void init(final Context context) {        final ActivityManager activityManager = (ActivityManager)context                .getSystemService(Context.ACTIVITY_SERVICE);        final int lruCacheSize = Math.round(0.25f * activityManager.getMemoryClass()                * 1024 * 1024);//四舍五入计算二级缓存大小        mLruCache = new LruCache
(lruCacheSize) {            @Override            protected int sizeOf(final String paramString, final Bitmap paramBitmap) {             //返回每个key所对应的values在二级缓存中报占大小                 return paramBitmap.getByteCount();            }        };    }    /**     * 查找或创建的高速缓存     * @param activity     * @return     */    public static final ImageCache findOrCreateCache(final Activity activity) {          FragmentManager nFragmentManger = activity.getFragmentManager();        RetainFragment retainFragment = (RetainFragment)nFragmentManger.findFragmentByTag(TAG);        if (retainFragment == null) {            retainFragment = new RetainFragment();            nFragmentManger.beginTransaction().add(retainFragment, TAG).commit();        }        ImageCache cache = (ImageCache)retainFragment.getObject();        if (cache == null) {            cache = getInstance(activity);            retainFragment.setObject(cache);        }        return cache;    }    /**     * 存入缓存     * @param data     * @param bitmap     */    public void add(final String data, final Bitmap bitmap) {        if (data == null || bitmap == null) {            return;        }        if (get(data) == null) {            mLruCache.put(data, bitmap);        }    }    /**     * 获取缓存图片     * @param data     * @return     */    public final Bitmap get(final String data) {        if (data == null) {            return null;        }        if (mLruCache != null) {            final Bitmap mBitmap = mLruCache.get(data);            if (mBitmap != null) {                return mBitmap;            }        }        return null;    }    /**     * 移除指定缓存     */    public void remove(final String key) {        if (mLruCache != null) {            mLruCache.remove(key);        }    }        /**     * 清除缴存并回收     */    public void clearMemCache() {        if (mLruCache != null) {            mLruCache.evictAll();        }        System.gc();    }    /**     * 个人理解为是 保持应用(FragmentManager)只存在这一个实例     * @author xiajun     *     */    public static final class RetainFragment extends Fragment {        private Object mObject;        public RetainFragment() {        }        @Override        public void onCreate(final Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            // Make sure this Fragment is retained over a configuration change            setRetainInstance(true);        }        public void setObject(final Object object) {            mObject = object;        }        public Object getObject() {            return mObject;        }    }}

ImageProvider.java

public class ImageProvider implements GetBitmapTask.OnBitmapReadyListener{    private ImageCache memCache;    private Map
> pendingImagesMap = new HashMap
>();    private Set
 unavailable = new HashSet
();        private Context mContext;        private int thumbSize;        private static  ImageProvider mInstance;        protected ImageProvider( Activity activity ) {     mContext = activity;     memCache = ImageCache.getInstance( activity );     Resources resources = mContext.getResources();     DisplayMetrics metrics = resources.getDisplayMetrics();     thumbSize = (int) ( ( 153 * (metrics.densityDpi/160f) ) + 0.5f );    }        public final static ImageProvider getInstance( final Activity activity ) {             if (mInstance == null) {            mInstance = new ImageProvider( activity );            mInstance.setImageCache(ImageCache.findOrCreateCache(activity));        }        return mInstance;            }        public void setImageCache(final ImageCache cacheCallback) {     memCache = cacheCallback;    }        /**     * 加载图片     * @param imageView 显示的View     * @param imageInfo 图片信息相关     */    public void loadImage( ImageView imageView, ImageInfo imageInfo ){     //创建一个图片标识,例如:21albartimg 图片命名和创建规则,请详细查看ImageUtils.java     String tag = ImageUtils.createShortTag(imageInfo) + imageInfo.size;     if( imageInfo.source.equals(SRC_FILE) || imageInfo.source.equals(SRC_LASTFM) || imageInfo.source.equals(SRC_GALLERY)){     clearFromMemoryCache( ImageUtils.createShortTag(imageInfo) );     asyncLoad( tag, imageView, new GetBitmapTask( thumbSize, imageInfo, this, imageView.getContext() ) ); }     if(!setCachedBitmap(imageView, tag)){            asyncLoad( tag, imageView, new GetBitmapTask( thumbSize, imageInfo, this, imageView.getContext() ) );        }    }    /**     * 缓存位图     * @param imageView     * @param tag     * @return     */    private boolean setCachedBitmap(ImageView imageView, String tag) {        if (unavailable.contains(tag)) {            handleBitmapUnavailable(imageView, tag);            return true;        }        Bitmap bitmap = memCache.get(tag);        if (bitmap == null)            return false;        imageView.setTag(tag);        imageView.setImageBitmap(bitmap);        return true;    }    /**     * 处理位图不可用     * @param imageView     * @param tag     */    private void handleBitmapUnavailable(ImageView imageView, String tag) {        imageView.setTag(tag);        imageView.setImageDrawable(null);    }    /**     * 加载位图     * @param imageView     * @param bitmap     * @param tag     */    private void setLoadedBitmap(ImageView imageView, Bitmap bitmap, String tag) {        if (!tag.equals(imageView.getTag()))            return;        final TransitionDrawable transition = new TransitionDrawable(new Drawable[]{                new ColorDrawable(android.R.color.transparent),                new BitmapDrawable(imageView.getResources(), bitmap)        });        imageView.setImageDrawable(transition);        final int duration = imageView.getResources().getInteger(R.integer.image_fade_in_duration);        transition.startTransition(duration);    }    /**     * 异步加载     * @param tag     * @param imageView     * @param task     */    private void asyncLoad(String tag, ImageView imageView, AsyncTask
 task) {        Set
 pendingImages = pendingImagesMap.get(tag);        if (pendingImages == null) {            pendingImages = Collections.newSetFromMap(new WeakHashMap
()); // create weak set            pendingImagesMap.put(tag, pendingImages);            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);//可用于并行执行任务的执行        }        pendingImages.add(imageView);        imageView.setTag(tag);        imageView.setImageDrawable(null);    }    @Override    public void bitmapReady(Bitmap bitmap, String tag) {        if (bitmap == null) {            unavailable.add(tag);        }        else        {            memCache.add(tag, bitmap);        }        Set
 pendingImages = pendingImagesMap.get(tag);        if (pendingImages != null) {            pendingImagesMap.remove(tag);            for (ImageView imageView : pendingImages) {                setLoadedBitmap(imageView, bitmap, tag);            }        }    }        /**     * 清除内存缓存     * @param tag     */    public void clearFromMemoryCache(String tag){        if (unavailable.contains(tag + SIZE_THUMB)) {         unavailable.remove(tag + SIZE_THUMB);        }        if (pendingImagesMap.get(tag + SIZE_THUMB)!=null){         pendingImagesMap.remove(tag + SIZE_THUMB);        }        if (memCache.get(tag + SIZE_THUMB)!=null){         memCache.remove(tag + SIZE_THUMB);        }        if (unavailable.contains(tag + SIZE_NORMAL)) {         unavailable.remove(tag + SIZE_NORMAL);        }        if (pendingImagesMap.get(tag + SIZE_NORMAL)!=null){         pendingImagesMap.remove(tag + SIZE_NORMAL);        }        if (memCache.get(tag + SIZE_NORMAL)!=null){         memCache.remove(tag + SIZE_NORMAL);        }    }        /**     * 清除所有缓存(内存和磁盘)     */    public void clearAllCaches(){     try{     ImageUtils.deleteDiskCache(mContext);     memCache.clearMemCache();     }     catch(Exception e){}    }}

GetBitmapTask.java

public class GetBitmapTask extends AsyncTask
 {        private WeakReference
 mListenerReference;    private WeakReference
 mContextReference;    private ImageInfo mImageInfo;        private int mThumbSize;    public GetBitmapTask( int thumbSize, ImageInfo imageInfo, OnBitmapReadyListener listener, Context context ) {        mListenerReference = new WeakReference
(listener);        mContextReference = new WeakReference
(context);        mImageInfo = imageInfo;     mThumbSize = thumbSize;    }    @Override    protected Bitmap doInBackground(String... ignored) {        Context context = mContextReference.get();        if (context == null) {            return null;        }        //返回图像信息来源于...        File nFile = null;                if( mImageInfo.source.equals(SRC_FILE)  && !isCancelled()){         nFile = ImageUtils.getImageFromMediaStore( context, mImageInfo );        }        else if ( mImageInfo.source.equals(SRC_LASTFM)  && !isCancelled()){         nFile = ImageUtils.getImageFromWeb( context, mImageInfo );        }        else if ( mImageInfo.source.equals(SRC_GALLERY)  && !isCancelled()){         nFile = ImageUtils.getImageFromGallery( context, mImageInfo );        }                 else if ( mImageInfo.source.equals(SRC_FIRST_AVAILABLE)  && !isCancelled()){         Bitmap bitmap = null;         if( mImageInfo.size.equals( SIZE_NORMAL ) ){         bitmap = ImageUtils.getNormalImageFromDisk( context, mImageInfo );         }         else if( mImageInfo.size.equals( SIZE_THUMB ) ){         bitmap = ImageUtils.getThumbImageFromDisk( context, mImageInfo, mThumbSize );         }         //if we have a bitmap here then its already properly sized         if( bitmap != null ){         return bitmap;         }                  if( mImageInfo.type.equals( TYPE_ALBUM ) ){         nFile = ImageUtils.getImageFromMediaStore( context, mImageInfo );         }         if( nFile == null && ( mImageInfo.type.equals( TYPE_ALBUM ) || mImageInfo.type.equals( TYPE_ARTIST ) ) )         nFile = ImageUtils.getImageFromWeb( context, mImageInfo );        }        if( nFile != null ){                  //返回正常大小的图         if( mImageInfo.size.equals( SIZE_NORMAL ) )         return BitmapFactory.decodeFile(nFile.getAbsolutePath());         //返回缩略图         return ImageUtils.getThumbImageFromDisk( context, nFile, mThumbSize );        }        return null;    }        @Override    protected void onPostExecute(Bitmap bitmap) {        super.onPostExecute(bitmap);        OnBitmapReadyListener listener = mListenerReference.get();        if(bitmap == null && !isCancelled()){         if(mImageInfo.size.equals(SIZE_THUMB))         bitmap = BitmapFactory.decodeResource(mContextReference.get().getResources(),         R.drawable.no_art_small);         else if(mImageInfo.size.equals(SIZE_NORMAL))         bitmap = BitmapFactory.decodeResource(mContextReference.get().getResources(),         R.drawable.no_art_normal);        }        if (bitmap != null && !isCancelled()) {            if (listener != null) {                 listener.bitmapReady(bitmap,  ImageUtils.createShortTag(mImageInfo) + mImageInfo.size );            }        }    }    public static interface OnBitmapReadyListener {        public void bitmapReady(Bitmap bitmap, String tag);    }}

下面看看ImageUtils这个类的格式命名规则

ImageUtils.java

public class ImageUtils {		//图片格式    private static final String IMAGE_EXTENSION = ".img";		private static File getFile(Context context, ImageInfo imageInfo){		return new File(context.getExternalCacheDir(), createShortTag(imageInfo)+IMAGE_EXTENSION);	}		/**	 * 从磁盘中获取正常图片	 * @param context	 * @param imageInfo	 * @return	 */	public static Bitmap getNormalImageFromDisk( Context context, ImageInfo imageInfo ){		Bitmap bitmap = null;		File nFile = getFile( context, imageInfo );		if(nFile.exists()){			bitmap = BitmapFactory.decodeFile( nFile.getAbsolutePath() );		}				return bitmap;	}		/**	 * 从磁盘中获取指定大小的缩略图片	 * @param context	 * @param imageInfo	 * @param thumbSize	 * @return	 */	public static Bitmap getThumbImageFromDisk( Context context, ImageInfo imageInfo, int thumbSize ){		File nFile = getFile( context, imageInfo );		return getThumbImageFromDisk( context, nFile, thumbSize );	}			/**	 * 从磁盘中获取指定大小的缩略图片	 * @param context	 * @param nFile	 * @param thumbSize	 * @return	 */	public static Bitmap getThumbImageFromDisk( Context context, File nFile, int thumbSize ){		if(!nFile.exists())			return null;		final BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = true;        try{        	BitmapFactory.decodeFile( nFile.getAbsolutePath() , options);        }        catch(Exception e){        }        final int height = options.outHeight;        final int width = options.outWidth;        int inSampleSize = 1;        if (height > thumbSize || width > thumbSize) {             if (width > height) {                 inSampleSize = Math.round((float)height / (float)thumbSize);             } else {                 inSampleSize = Math.round((float)width / (float)thumbSize);             }             final float totalPixels = width * height;             final float totalReqPixelsCap = thumbSize * thumbSize * 2;             while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {                 inSampleSize++;             }        }        options.inSampleSize = inSampleSize;        options.inJustDecodeBounds = false;        Bitmap bitmap = null;		try{			bitmap = BitmapFactory.decodeFile( nFile.getAbsolutePath() , options );		}		catch (Exception e){		}        return  bitmap;	}	/**	 * 获取相册中的图片	 * @param context	 * @param imageInfo	 * @return	 */	public static File getImageFromGallery( Context context, ImageInfo imageInfo ){				String albumArt = ( imageInfo.type == TYPE_ALBUM ) ? imageInfo.data[3] : imageInfo.data[1];	          if(albumArt != null){        	try{        		File orgFile = new File(albumArt);        		File newFile = new File(context.getExternalCacheDir(), createShortTag(imageInfo)+IMAGE_EXTENSION);        		InputStream in = new FileInputStream(orgFile);        		OutputStream out = new FileOutputStream(newFile);        		byte[] buf = new byte[1024];        		int len;        		while ((len = in.read(buf)) > 0){        			out.write(buf, 0, len);        		}        		in.close();        		out.close();	        	return newFile;        	}        	catch( Exception e){        	}        }        return null;	}		/**	 * 获取Web的图片	 * @param context	 * @param imageInfo	 * @return	 */    public static File getImageFromWeb( Context context, ImageInfo imageInfo ) {    	String imageUrl = null;        try {	        if( imageInfo.type.equals(TYPE_ALBUM) ){  	        	Album image = Album.getInfo(imageInfo.data[1], imageInfo.data[2], LASTFM_API_KEY);	            if (image != null) {	            	imageUrl = image.getLargestImage();	            }	        }	        else if ( imageInfo.type.equals(TYPE_ARTIST) ) {		        PaginatedResult images = Artist.getImages(imageInfo.data[0], 2, 1, LASTFM_API_KEY);	            Iterator iterator = images.getPageResults().iterator();	            if (iterator.hasNext()) {		            Image image = iterator.next();				        imageUrl = image.getLargestImage();	            }	        }        } catch ( Exception e ) {        	return null;        }        if ( imageUrl == null || imageUrl.isEmpty() ) {            return null;        }        File newFile = getFile( context, imageInfo );        ApolloUtils.downloadFile( imageUrl, newFile );		if (newFile.exists()) {            return newFile;        }        return null;    }        /**     * 获取多媒体图片     * @param context     * @param imageInfo     * @return     */    public static File getImageFromMediaStore( Context context, ImageInfo imageInfo ){    	String mAlbum = imageInfo.data[0];    	String[] projection = {                BaseColumns._ID, Audio.Albums._ID, Audio.Albums.ALBUM_ART, Audio.Albums.ALBUM        };        Uri uri = Audio.Albums.EXTERNAL_CONTENT_URI;        Cursor cursor = null;        try{        	cursor = context.getContentResolver().query(uri, projection, BaseColumns._ID+ "=" + DatabaseUtils.sqlEscapeString(mAlbum), null, null);        }        catch(Exception e){        	e.printStackTrace();        	        }        int column_index = cursor.getColumnIndex(Audio.Albums.ALBUM_ART);        if(cursor.getCount()>0){	    	cursor.moveToFirst();	        String albumArt = cursor.getString(column_index);	  	        if(albumArt != null){	        	try{	        		File orgFile = new File(albumArt);	        		File newFile = new File(context.getExternalCacheDir(), createShortTag(imageInfo)+IMAGE_EXTENSION);	        		InputStream in = new FileInputStream(orgFile);	        		OutputStream out = new FileOutputStream(newFile);	        		byte[] buf = new byte[1024];	        		int len;	        		while ((len = in.read(buf)) > 0){	        			out.write(buf, 0, len);	        		}	        		in.close();	        		out.close();	        		cursor.close();		        	return newFile;	        	}	        	catch( Exception e){	        	}	        }        }        return null;    }        /**     * 删除磁盘缓存     * @param context     * @throws IOException     */    public static void deleteDiskCache(Context context) throws IOException {    	final File dir = context.getExternalCacheDir();        final File[] files = dir.listFiles();        for (final File file : files) {            if (!file.delete()) {                throw new IOException("failed to delete file: " + file);            }        }    }        /**     * 创建图片标识     * @param imageInf     * @return     */    public static String createShortTag(ImageInfo imageInf){    	String tag = null;    	if( imageInf.type.equals( TYPE_ALBUM ) ){    		//专辑 id + 专辑后缀     		tag = imageInf.data[0] + ALBUM_SUFFIX;    	}    	else if (imageInf.type.equals( TYPE_ARTIST )){    		//艺术家名称 + 艺术家后缀    		tag = imageInf.data[0] + ARTIST_SUFFIX;    	}    	else if (imageInf.type.equals( TYPE_GENRE )){    		//流派名称 + 流派后缀    		tag = imageInf.data[0] + GENRE_SUFFIX;    	}    	else if (imageInf.type.equals( TYPE_PLAYLIST )){    		//流派名称 + 播放列表后缀    		tag = imageInf.data[0] + PLAYLIST_SUFFIX;    	}    	ApolloUtils.escapeForFileSystem(tag);    	return tag;    }    }

【Apollo播放器】图片加载模式,就说到这里,期待后面更多代码分析....

转载于:https://my.oschina.net/oppo4545/blog/205394

你可能感兴趣的文章
treap bzoj1503
查看>>
Java linkedList详细介绍及使用示例
查看>>
偏函数
查看>>
angular2怎么获取下拉框的值
查看>>
[转]NMON服务器监控、指标说明
查看>>
Cadence OrCAD Cpature创建Title Block
查看>>
数据强转
查看>>
HDU-4342 History repeat itself 二分
查看>>
C# 实现快捷键几种方法
查看>>
说说Android桌面(Launcher应用)背后的故事(三)——CellLayout的秘密
查看>>
Latest crack software ftp download
查看>>
制作毛玻璃效果 分类: ios技术 2015-07-...
查看>>
javascript中加号(+)操作符的作用
查看>>
修改host文件屏蔽视频广告和网站
查看>>
mapreduce多文件输出的两方法
查看>>
JAVA 内存详解 (理解 JVM 如何使用 Windows 和 Linux 上的本机内存)
查看>>
Spring Boot (十三): Spring Boot 小技巧
查看>>
MySql Connector/NET MySql.Data.Entity.EF6 6.9.5 Contains 语句
查看>>
File.basename
查看>>
java的对象的总结:(PO,VO,DAO,BO,POJO)
查看>>