Android SmartImageView源码分析
来源:互联网 发布:淘宝工具软件 编辑:程序博客网 时间:2024/06/05 18:13
前言:突然想把用过的图片加载的框架整理下,SmartImageView是所使用的最早的网络加载图片的小框架了,当时还为它的强大惊叹不已。不过也好久没使用过了,因为它的还算比较简单,就作为开源框架源码分析之旅的开端吧。
一、源码下载
SmartImageView也是托管在GitHub的一个开源项目,在GitHub下载到源码。下载地址
下载到的源码为6个类,我一般习惯用库的形式把框架加载到我的工程中去,所以我建立了一个项目然后把这6个类考进去,然后把项目作为library。 OK,初步工作就做好了。
先看下SmartImageView的自我介绍:Android ImageView replacement which allows image loading from URLs or contact address book, with caching. 可以大致看出SmartImageView是ImageView的一种加强形式,它具有缓存机制并且能直接加载网络图片以及通讯录图片。
二、实例应用
那么来举个例子吧:
先看下布局文件,很简单一个SmartImageView控件,一个按钮:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.loopj.android.image.SmartImageView android:id="@+id/main_act_siv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> <Button android:id="@+id/main_act_btn" android:text="点击加载网络图片" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content" /></RelativeLayout>
然后是MainActivity中,也是很简单,设置按钮的监听,当点击的时候就去给SmartImageView设置网络图片:
/** SmartImageView控件 */ private SmartImageView mSmartImageView; /** 加载网络图片按钮 */ private Button loadImage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSmartImageView = (SmartImageView) this.findViewById(R.id.main_act_siv); loadImage = (Button)this.findViewById(R.id.main_act_btn); loadImage.setOnClickListener(this); // 加载图片按钮监听设置 } @Override public void onClick(View v) { switch (v.getId()) { case R.id.main_act_btn: mSmartImageView.setImageUrl("http://pic6.nipic.com/20100317/4085465_113938064402_2.jpg"); break;} }
需要注意的一点是,这里有访问网络的操作,需要添加网络访问权限。
<uses-permission android:name="android.permission.INTERNET"/>整体效果图:
三、源码分析
我们就一点点的点进去看看吧,首先从SmartImageView的setImageUrl看起:
// Helpers to set image by URL public void setImageUrl(String url) { setImage(new WebImage(url)); } public void setImageUrl(String url, SmartImageTask.OnCompleteListener completeListener) { setImage(new WebImage(url), completeListener); } public void setImageUrl(String url, final Integer fallbackResource) { setImage(new WebImage(url), fallbackResource); } public void setImageUrl(String url, final Integer fallbackResource, SmartImageTask.OnCompleteListener completeListener) { setImage(new WebImage(url), fallbackResource, completeListener); } public void setImageUrl(String url, final Integer fallbackResource, final Integer loadingResource) { setImage(new WebImage(url), fallbackResource, loadingResource); } public void setImageUrl(String url, final Integer fallbackResource, final Integer loadingResource, SmartImageTask.OnCompleteListener completeListener) { setImage(new WebImage(url), fallbackResource, loadingResource, completeListener); }
可以看到有一大串重载的方法,可以设置加载的网络图片url,加载中显示的图片id,加载失败显示的图片id,以及加载完成的接口回调等等,在示例中调用的是最简单的只有一个参数的方法。
public void setImageUrl(String url) { setImage(new WebImage(url)); }
setImage()这里传入了一个WebImage的对象,跟进入看下具体代码:
public void setImage(final SmartImage image, final Integer fallbackResource, final Integer loadingResource, final SmartImageTask.OnCompleteListener completeListener) { // 设置下载的时候显示的图片,这里我们传入的参数为空,不去关心 if(loadingResource != null){ setImageResource(loadingResource); } // 停止正在为该SmartImageView下载网络图片的线程,代码健壮性考虑,不去关心 if(currentTask != null) { currentTask.cancel(); currentTask = null; } // 创建一个新的线程 currentTask = new SmartImageTask(getContext(), image); // SmartImageTask实现Runnable方法 currentTask.setOnCompleteHandler(new SmartImageTask.OnCompleteHandler() { @Override public void onComplete(Bitmap bitmap) { if(bitmap != null) { setImageBitmap(bitmap); } else { // 如果下载失败,责显示预设的加载失败时显示的图片 if(fallbackResource != null) { setImageResource(fallbackResource); } } // 设置图片下载完成的回调回调,这里我们传入的参数为空,不去关心 if(completeListener != null){ completeListener.onComplete(bitmap); } } }); // 将该下载图片的线程添加到线程池中并执行 threadPool.execute(currentTask); }
可以看到,这在里执行了设置图片的操作,在下载之前设置显示为预设的加载之前的图片,然后先将currentTask置为空,然后创建新Task,即SmartImageView只是展示图片的作用,获取图片的操作在将currentTask添加到theadPool线程池后去执行。既然SmartImageTask实现了Runnable接口,那肯定重要的方法就是复写的run方法了。
@Override public void run() { if(image != null) { complete(image.getBitmap(context)); context = null; } }
在run方法中只执行了一个方法complete(),但是作为参数的image.getBitmap()绝对是该框架的核心代码,在该方法中去获取了图片,并返还获取到的图片。
public Bitmap getBitmap(Context context) { // Don't leak context if(webImageCache == null) { webImageCache = new WebImageCache(context); } // Try getting bitmap from cache first Bitmap bitmap = null; if(url != null) { bitmap = webImageCache.get(url); if(bitmap == null) { bitmap = getBitmapFromUrl(url); if(bitmap != null){ webImageCache.put(url, bitmap); } } } return bitmap; }
可见在这里加入了缓存机制,稍后再认真分析缓存机制,先瞄一眼网络下载的方法:
private Bitmap getBitmapFromUrl(String url) { Bitmap bitmap = null; try { URLConnection conn = new URL(url).openConnection(); conn.setConnectTimeout(CONNECT_TIMEOUT); conn.setReadTimeout(READ_TIMEOUT); bitmap = BitmapFactory.decodeStream((InputStream) conn.getContent()); } catch(Exception e) { e.printStackTrace(); } return bitmap; }
可见网络下载图片的方法还算写的比较简单的,没有考虑到会出现内存溢出的情况,接着看些complete()方法:
public void complete(Bitmap bitmap){ if(onCompleteHandler != null && !cancelled) { onCompleteHandler.sendMessage(onCompleteHandler.obtainMessage(BITMAP_READY, bitmap)); } }
通过这个方法执行的必要条件也看到了在SmartImageView的setImage()中设置setOnCompleteHandler()的必要性,这里是通过传递的Handler对象来进行Handler消息机制的传递的,将获取到的图片通过Handler发送到主线程去执行更新界面的操作,既然是Handler机制,那么重要的方法肯定是handleMessage()方法了。
public static class OnCompleteHandler extends Handler { @Override public void handleMessage(Message msg) { Bitmap bitmap = (Bitmap)msg.obj; onComplete(bitmap); } public void onComplete(Bitmap bitmap){}; }
这个就是我们在SmartImageView中创建的Handler实例对象的主体,通过handleMessage()中调用的onComplete方法将获取到的图片回调给SmartImageView进行处理。
总结下上面分析的过程:
ok,到此访问网络下载图片并显示到界面的过程就分析清楚了。
四、缓存机制分析
其实在源码分析中给出的getBitmap()的代码只是WebImage的一个实现,为什么这么说呢?来看一下类图:
获取图片:
public Bitmap get(final String url) { Bitmap bitmap = null; // Check for image in memory bitmap = getBitmapFromMemory(url); // Check for image on disk cache if(bitmap == null) { bitmap = getBitmapFromDisk(url); // Write bitmap back into memory cache if(bitmap != null) { cacheBitmapToMemory(url, bitmap); } } return bitmap; }通过以上可以看到,在缓存获取的时候首先在内存缓存中去获取,如果内存缓存中没有责去sdcard缓存中去获取,返回获取的bitmap,如果都没有获取到责返回null;接下来分别看下具体是如何获取缓存图片的。
private Bitmap getBitmapFromMemory(String url) { Bitmap bitmap = null; SoftReference<Bitmap> softRef = memoryCache.get(getCacheKey(url)); if(softRef != null){ bitmap = softRef.get(); } return bitmap; }获取内存缓存,内存缓存的机制是Map的键为String类型的图片url地址(经过转换后的),值为软引用类型的bitmap对象,如果获取到该url对应的图片则将其返回;
private Bitmap getBitmapFromDisk(String url) { Bitmap bitmap = null; if(diskCacheEnabled){ String filePath = getFilePath(url); File file = new File(filePath); if(file.exists()) { bitmap = BitmapFactory.decodeFile(filePath); } } return bitmap; }获取sdcard缓存,sdcard缓存的机制是将url地址(经过转换后的)作为文件的名字,将bitmap保存为文件,如果获取到该url对应的图片则将其返回;
保存图片:
public void put(String url, Bitmap bitmap) { cacheBitmapToMemory(url, bitmap); cacheBitmapToDisk(url, bitmap); }可以看到在网络获取到图片之后分别将该bitmap缓存到内存以及sdcard中:
private void cacheBitmapToMemory(final String url, final Bitmap bitmap) { memoryCache.put(getCacheKey(url), new SoftReference<Bitmap>(bitmap)); }
private void cacheBitmapToDisk(final String url, final Bitmap bitmap) { writeThread.execute(new Runnable() { @Override public void run() { if(diskCacheEnabled) { BufferedOutputStream ostream = null; try { ostream = new BufferedOutputStream(new FileOutputStream(new File(diskCachePath, getCacheKey(url))), 2*1024); bitmap.compress(CompressFormat.PNG, 100, ostream); } catch (FileNotFoundException e) { e.printStackTrace(); } finally { try { if(ostream != null) { ostream.flush(); ostream.close(); } } catch (IOException e) {} } } } }); }
五、下载传送门
- Android SmartImageView源码分析
- Android SmartImageView使用实例
- Android 自定义smartImageView
- SmartImageView
- SmartImageView
- SmartImageView
- SmartImageView
- SmartImageView
- SmartImageView
- SmartImageView
- Android框架——SmartImageView
- Android学习(46) -- SmartImageView
- 【Android之SmartImageView图片控件】
- Android--Android图像开源视图:SmartImageView
- Android图像开源视图:SmartImageView
- Android图像开源视图:SmartImageView
- Android图像开源视图:SmartImageView
- Android图像开源视图:SmartImageView
- cocos2dx3.2 往模板build_native.py加入java库脚本
- 聊聊高并发(三十七)整理一下并发基础中的一些知识点
- 1163 访问艺术馆
- Android控件TextView学习一
- SQL Server 2008 R2
- Android SmartImageView源码分析
- LCT系列
- 用PendingIntent传送数据丢失解决办法
- Dalvik虚拟机相关的可执行程序
- UVa 490 - Rotating Sentences
- 静态绑定与动态绑定
- Ubuntu安装可视化的c++编译器
- 第十七周项目四 日期结构体
- 普通用户登录EM