XUtils BitmapUtils 改造以添加drawable支持

=== XUtilsBitmapUtils 改造以添加drawable支持 ===

# XUtils 简介

XUtils 是一套少有的早期国产安卓框架, 其源于AFinal, 目录结构也与之相似, 但是代码却进行了大量的重构, 是XUtils更加现代, 解决了AFinal 的OOM等问题.

目前 XUtils 已经支持 API 8(android 2.2) 至 API 21(android 5.0.x).

XUtils 主要内置了DbUtils 模块, ViewUtils 模块, HttpUtils 模块, BitmapUtils 模块.

对于新手来说, 这些功能着实使用而且强大, 为我们省下了不少的功夫 去处理业务.

同类的框架, 国外流行的的有androidannotations, roboguice, androidquery,droidparts等, 当然国内也有不少竞争者,

ThinkAndroid,UltimateAndroid, LoonAndroid, KJFrameForAndroid, SmartAndroid, 都是可以可以用来借鉴的. 本文暂时专注于XUtils的使用.

具体的细化模块可以参考 官方地址(wyouflf/xUtils):

https://github.com/wyouflf/xUtils

做过android的同学一定都知道安卓处理Bitmap可谓一绝, Bitmap绝对是吃内存的大户, 而且Dalvik虚拟机(暂时不考虑ART技术)垃圾回收经常不及时, 所以图片处理不当,经常会出现OOM(out of memory), 即内存溢出的情况. 在接触XUtils等框架之前, 很多人都是自己通过BitmapFactory.Options 来解决燃眉之急, 网上也有很多对策, 但是这样很不系统, 而且有些方案, 例如使用软引用或者弱引用, 已经在安卓4之后不再被推荐,
仍然可能会出现OOM. 所以一款流行的, 稳定的, 现代的代码框架是必不可少的. XUtils 恰恰满足了这一点.

XUtils 的图片处理存在缓存, 主要是内存缓存和外存缓存. 但是这不是今天本文的重点, 但是以后会提及. 今天主要说说XUtils不太好的方面, 首先直接上修改过的官方代码:

// this 是一个 Context

BitmapUtilsbitmapUtils = new BitmapUtils(this);

// 加载网络图片

bitmapUtils.display(testImageView,"http://www.52deng.com/logo.png");

bitmapUtils.display(testImageView,"ftp://www.52deng.com/logo.png");

// 加载本地图片, 路径以/开头, 需要填写绝对路径

bitmapUtils.display(testImageView,"/sdcard/dengdeng/test.jpg");

// 加载assets中的图片, 路径以assets开头

bitmapUtils.display(testImageView,"assets/dengdeng/wallpaper.jpg");

// 使用ListView等容器展示图片时, 可通过PauseOnScrollListener在滑动和快速滑动过程中控制暂停加载图片

listView.setOnScrollListener(newPauseOnScrollListener(bitmapUtils, false, true));

listView.setOnScrollListener(newPauseOnScrollListener(bitmapUtils, false, true, customListener));

注释已经被我优化, 相信结合代码, 语义应该更加明朗了. (← 你够了, 语文渣)

但是仔细观察会发现, 其实UXtils还是有不完美的地方: 貌似并不支持从项目中的drawable获取图片进行展示, 这样岂不是遇到大图片又要回归BitmapFactory.Options等基础方案了吗? 这里给大家推荐一下另一个安卓专攻图片处理的框架Android-Universal-Image-Loader, 官方地址如下:

https://github.com/nostra13/Android-Universal-Image-Loader,

看关注度就能看出来, 它在Github上处于垄断地位, 当然还有其他的专攻网络和图片异步的框架(国外的有glide, ion, Picasso,volley等), 都是很厉害和出名的. 那么我们来看看 他支持的图片处理方案, 不改了, 直接引用官方的例子:

"http://site.com/image.png"// from Web

"file:///mnt/sdcard/image.png"// from SD card

"file:///mnt/sdcard/video.mp4"// from SD card (video thumbnail)

"content://media/external/images/media/13"// from content provider

"content://media/external/video/media/13"// from content provider (video thumbnail)

"assets://image.png"// from assets

"drawable://"+ R.drawable.img//
fromdrawables (non-9patch images)

NOTE: Use drawable:// only
if you really need it! Always considerthe native way toload drawables -ImageView.setImageResource(...) instead
of using of ImageLoader.

看, 他是 支持多种图片协议或者存储路径的, 也包括drawable, 但是值得注意的是, 他其实并不推荐缓存drawable, 根据我的理解, 毕竟有一些drawable很小, 直接使用 ImageView 等空间自带的放置图片的方法即可. 但是遇到OOM的话, 该出手时就出手. 由于时间紧迫, 暂时不细研究这款开源项目的设计, 直接扒代码. 检出项目之后, Ctrl+H选择项目, 全文搜索 关键字”drawable://”.
结果出来一堆东西, 换个思路, 搜索”assets://”, 居然找到的是例子, 再换思路, 搜索”assets:”, ok, 侥幸找到了核心代码 (其实他是通过 scheme 匹配传递的url的协议的):

// com.nostra13.universalimageloader.core.download.BaseImageDownloader.java

@Override

public InputStream getStream(StringimageUri,
Object extra) throws IOException{

switch (Scheme.ofUri(imageUri)) {

caseHTTP:

caseHTTPS:

return getStreamFromNetwork(imageUri,extra);

caseFILE:

return getStreamFromFile(imageUri,extra);

caseCONTENT:

return getStreamFromContent(imageUri,extra);

caseASSETS:

return getStreamFromAssets(imageUri,extra);

caseDRAWABLE:

return getStreamFromDrawable(imageUri,extra);

caseUNKNOWN:

default:

return getStreamFromOtherSource(imageUri,extra);

}

}

好吧, 把DRAWABLE看看:

protected InputStream getStreamFromDrawable(StringimageUri,Object
extra) {

String
drawableIdString = Scheme.DRAWABLE.crop(imageUri);

int drawableId =Integer.parseInt(drawableIdString);

return context.getResources().openRawResource(drawableId);

}

OK了, 那么来匹配一下 Xutils, 开启Ctrl+H全文搜索打开, 搜索”assets”, 轻松找到了:

// com.lidroid.xutils.bitmap.download.DefaultDownloader.java

if (uri.startsWith("/")) {

FileInputStream fileInputStream =newFileInputStream(uri);

fileLen =
fileInputStream.available();

bis =
new
BufferedInputStream(fileInputStream);

result =
System
.currentTimeMillis() +
this
.getDefaultExpiry();

} else
if
(uri.startsWith("assets/")) {

InputStream
inputStream = this.getContext().getAssets().open(uri.substring(7,uri.length()));

fileLen =
inputStream.available();

bis =
new
BufferedInputStream(inputStream);

result =
Long
.MAX_VALUE;

} else {

final URLurl =newURL(uri);

urlConnection =url.openConnection();

urlConnection.setConnectTimeout(this.getDefaultConnectTimeout());

urlConnection.setReadTimeout(this.getDefaultReadTimeout());

bis =
new
BufferedInputStream(urlConnection.getInputStream());

result =
urlConnection.getExpiration();

result =
result < System.currentTimeMillis() ?System.currentTimeMillis() +this.getDefaultExpiry()
:result;

fileLen =
urlConnection.getContentLength();

}

}

有了前几步的经验, 轻松改造, 加一个else if, 代码 参考之前的Android-Universal-Image-Loader的核心代码:

if (uri.startsWith("/")) {

FileInputStream fileInputStream =newFileInputStream(uri);

fileLen =
fileInputStream.available();

bis =
new
BufferedInputStream(fileInputStream);

result =
System
.currentTimeMillis() +
this
.getDefaultExpiry();

} else
if
(uri.startsWith("assets/")) {

InputStream
inputStream = this.getContext().getAssets().open(uri.substring(7,uri.length()));

fileLen =
inputStream.available();

bis =
new
BufferedInputStream(inputStream);

result =
Long
.MAX_VALUE;

} else
if
(uri.startsWith("drawable://")) {//赤裸裸地抄袭,我也用这个协议

String
drawableIdString = uri.substring(11,uri.length());//注意别算错了

intdrawableId =Integer.parseInt(drawableIdString);
//还原原始的 id

InputStream
inputStream = this.getContext().getResources().openRawResource(drawableId);

fileLen =
inputStream.available();//抄上面的

bis =
new
BufferedInputStream(inputStream); //抄上面的

result =
Long
.MAX_VALUE;//抄上面的,先这么写,
以后讨论

} else {

final URLurl =newURL(uri);

urlConnection =url.openConnection();

urlConnection.setConnectTimeout(this.getDefaultConnectTimeout());

urlConnection.setReadTimeout(this.getDefaultReadTimeout());

bis =
new
BufferedInputStream(urlConnection.getInputStream());

result =
urlConnection.getExpiration();

result =
result < System.currentTimeMillis() ?System.currentTimeMillis() +this.getDefaultExpiry()
:result;

fileLen =
urlConnection.getContentLength();

}

}

轻松改造, TEST!!

String uri = "drawable://" +R.drawable.super_larger_logo;

BitmapHelp.getBitmapUtils(this).display(largePic_imgV, uri);

OK, 测试通过, 图片出现, 未出现OOM. 至此, 成功地添加drawable支持. 同理, 我们也可以抄抄”content”等协议的代码, 本文就不赘述了, 注意源代码的协议, 引用或者修改都要留出处啊.

Presented byimknown

2015-03-13

时间: 2024-10-03 13:38:49

XUtils BitmapUtils 改造以添加drawable支持的相关文章

XUtils BitmapUtils 改造以加入drawable支持

=== XUtilsBitmapUtils 改造以加入drawable支持 === # XUtils 简单介绍 XUtils 是一套少有的早期国产安卓框架, 其源于AFinal, 文件夹结构也与之相似, 可是代码却进行了大量的重构, 使得XUtils更加现代, 攻克了AFinal 的OOM等问题. 眼下 XUtils 已经支持 API 8(android 2.2) 至 API 21(android 5.0.x). XUtils 主要内置了DbUtils 模块, ViewUtils 模块, Htt

我的Opencv4Android添加V4L2支持的移植记录(3)

博主QQ:1356438802 本文实验平台:Eclipse + Opencv 2.4.10 + MTK Android 4.4平板(这一直是我的Android实验平台) 可能各位看官,看到前面的文章会觉得很凌乱,一会儿这个平台,一会儿那个平台. 其实我的主要思路就是:opencv中的任何一个功能,首先在windows上验证成功,再到Ubuntu,然后到Android上验证! 在windows上,由于其系统通用性,各方面支持肯定更好,所以我一定能验证成功,然后我再去Android上面做这些功能.

为UiAutomatorViewer添加xpath支持

UiAutomatorViewer是Android SDK自带的测试工具,用来查看手机或模拟器上的界面元素,小巧,简单,开箱即用,十分方便.美中不足之处在于,它不能获取界面元素的xpath. 写自动化测试脚本时,xpath是一种非常方便的定位方式.Appium等一些成熟的工具框架可以获取到界面元素xpath,但使用起来稍有点重量级.那么是否也可以给UiAutomatorViewer添加xpath支持呢? 答案是肯定的. 首先下载UiAutomatorView源代码,我用的地址是https://a

为Gradle添加UTF-8支持

gradle默认使用系统字符编码,大多数中文系统是使用GBK编码 但程序员绝大部分都是使用UTF-8写各类java文件以及其他资源文件 编译时很容易报错,比如下面的错误: ”警告:编码 GBK 的不可映射字符“ 有两种办法可以给gradle添加UTF-8支持 第一种,在我们的项目配置文件build.gradle中最后添加下面的语句 tasks.withType(JavaCompile) { options.encoding = "UTF-8" } 这样,这个项目在进行gradle打包时

为UIAlertView添加block支持

系统自带的UIAlertView只能支持delegate方式. 如果你只有一个UIAlertView这种方式可能无关紧要. 但如果你有二个或多个UIAlertView, 你需要在委托方法中进行判断是哪个UIAlertView实例的产生的委托, 接着又要判断是响应哪个button. 如果你曾经这样做过, 想想这是多杂的代码. Objective-C是支持块代码的, 如果对UIAlertView添加块支持, 那岂不是一个美事. 这里推荐一个开源的实现: https://github.com/jiv

Ubuntu下安装VirtualBox并为其添加USB支持

1.下载VirtualBox软件包和USB支持包 下载网址均为为:https://www.virtualbox.org/wiki/Downloads VirtualBox软件包下载项: VirtualBox 4.3.10 for Linux hosts USB支持包下载项: VirtualBox 4.3.10 Oracle VM VirtualBox Extension Pack All supported platforms 2.下载完成后,进行安装 3.添加当前用户到组 sudo gedit

Qt国际化(Q_DECLARE_TR_FUNCTIONS() 宏给非Qt类添加翻译支持,以前没见过QTextEncoder和QTextDecoder和QLibraryInfo::location()和QEvent::LanguageChange)

Internationalization with Qt 应用程序的国际化就是使得程序能在国际间可用而不仅仅是在本国可用的过程. Relevant Qt Classes andAPIs 以下的类支持Qt的国际化. QTextCodec QTextDecoder QTextEncoder QTranslator QLocale Languages and WritingSystems 有时,国际化是比较简单的,例如,把美国的应用程序让澳大利亚或英国的用户可访问,只需要简单的改变拼写.但是,把美国的

在IntelliJ IDEA中添加框架支持时找不到Hibernate的解决办法

问题描述 第一次在Add Frameworks support界面中添加hibernate支持的时候,异常中断,导致没有成功添加. 第二次进入Add Frameworks support窗口时,发现找不到hibernate. 解决办法 打开项目根目录下的spring-mvc-crud.iml文件,搜索hibernate找到这段代码并删除,然后重新添加框架支持即可选择hibernate. <facet type="hibernate" name="Hibernate&qu

为Vim 添加vimgdb支持

为Vim 添加vimgdb支持 1.    下载最新的vim74的源码包 wget ftp://ftp.vim.org/pub/vim/unix/vim-7.4.tar.bz2 2.下载vimgdb-for-vim7.4源码 wget https://github.com/larrupingpig/vimgdb-for-vim7.4/archive/master.zip -O vimgdb-for-vim74.zip 3.解压所有文件,并应用补丁文件 tar xjvf vim-7.4.tar.b