Android ImageSwitcher 配合Picasso解决内存溢出(OOM)问题
最近项目中用到了 ImageSwitcher 来实现图片切换,使用起来很简单,但发现当图片比较大(超过了3M)时,程序出现了内存溢出(OOM)问题而崩溃了。
原因就是图片太大了,显示到 ImageView 上时,内存不够用了。而业界有几个很出名的图片库已经解决了加载大图片内存溢出问题,其中比较出名的就有 square 公司开发的 picasso 和 bumptech 开发的 Glide ,这两个库都很优秀,各有长处(关于这两个库的比较,请参考:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html)。
那么如何让 ImageSwitcher 跟 Picasso 配合使用呢?
布局上,只要让 ImageSwitcher 背景透明就可以了,然后在后面放一个 ImageView ,然后利用 ImageSwitcher 来做左右滑动效果,然后真正显示图片用背后的 ImageView 。
布局如下:
<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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/loading" />
<ImageView
android:id="@+id/ivShow"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:contentDescription="@string/empty"
android:scaleType="centerInside" />
<ImageSwitcher
android:id="@+id/isShowImages"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/transparent" />
</RelativeLayout>
关于 Picasso 的使用方法,这里不多说,请参考官方说明。这里要注意的有两点:
1、ImageSwitcher 实现中的 makeView 要设置为透明背景
2、Picasso 要调用 fit() 和 centerCrop() 对图片大小进行调整,从而极大节省内存
关键代码如下:
public class ShowImageActivity extends AppCompatActivity implements ViewSwitcher.ViewFactory, View.OnTouchListener {
private static final String TAG = "ShowImageActivity";
private ImageSwitcher mImageSwitcher;
private ImageView mIvShow;
private String mFolderPath;
private List<String> mImagePaths = new ArrayList<>();
private int mCurrentPosition = 0;
private File mCurrentImageFile;
private float mDownX;
private final Handler mHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_image);
mImageSwitcher = (ImageSwitcher) findViewById(R.id.isShowImages);
mImageSwitcher.setFactory(this);
mImageSwitcher.setOnTouchListener(this);
mIvShow = (ImageView) findViewById(R.id.ivShow);
mFolderPath = "图片所在文件夹路径";
loadData();
}
private void loadData() {
new Thread(new Runnable() {
@Override
public void run() {
File dir = new File(mFolderPath);
if (dir.exists()) {
File[] images = dir.listFiles();
if (images.length > 0) {
for (int i = 0, j = images.length; i < j; i++) {
File pic = images[i];
if (pic.isDirectory()) {
continue;
}
mImagePaths.add(pic.getAbsolutePath());
}
}
}
mHandler.obtainMessage().sendToTarget();
}
}).start();
}
private void handleMessage(Message msg) {
if (msg.what == 1) {
if (mCurrentImageFile != null) {
Picasso.with(this)
.load(mCurrentImageFile)
.fit()
.centerCrop()
.into(mIvShow);
}
} else {
if (mImagePaths.size() == 0) {
finish();
} else {
showPicture();
}
}
}
private void showPicture() {
new Thread(new Runnable() {
@Override
public void run() {
String imagePath = mImagePaths.get(mCurrentPosition);
mCurrentImageFile = new File(imagePath);
mHandler.obtainMessage(1).sendToTarget();
}
}).start();
}
@Override
public View makeView() {
final ImageView i = new ImageView(this);
i.setBackgroundColor(Color.TRANSPARENT);
return i;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
//手指按下的X坐标
mDownX = event.getX();
break;
}
case MotionEvent.ACTION_UP: {
float lastX = event.getX();
//抬起的时候的X坐标大于按下的时候就显示上一张图片
if (lastX > mDownX) {
if (mCurrentPosition > 0) {
//设置动画
mImageSwitcher.setInAnimation(AnimationUtils.loadAnimation(getApplication(), R.anim.left_in));
mImageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(getApplication(), R.anim.right_out));
mCurrentPosition--;
showPicture();
}
}
if (lastX < mDownX) {
if (mCurrentPosition < mImagePaths.size() - 1) {
mImageSwitcher.setInAnimation(AnimationUtils.loadAnimation(getApplication(), R.anim.right_in));
mImageSwitcher.setOutAnimation(AnimationUtils.loadAnimation(getApplication(), R.anim.left_out));
mCurrentPosition++;
showPicture();
}
}
}
break;
}
return true;
}
private static class MyHandler extends Handler {
private final WeakReference<ShowImageActivity> mActivity;
public MyHandler(ShowImageActivity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
ShowImageActivity activity = mActivity.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
}
注:其中去掉了部分与本文无关的逻辑代码。
ImageSwitcher 的使用部分参考了:http://blog.csdn.net/xiaanming/article/details/8988152
目前此方案可以解决OOM问题,但滑动时的效果没有了,后续再优化。
Android ImageSwitcher 配合Picasso解决内存溢出(OOM)问题的更多相关文章
- android解决内存溢出的问题(没有从根本上解决)
Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完 ...
- 内存溢出OOM与内存泄漏ML
附, 微信团队原创分享:Android内存泄漏监控和优化技巧总结 一.如何避免OOM 异常 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中 ...
- 内存溢出OOM
如何避免OOM 异常? 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang ...
- JVM:内存溢出OOM
JVM:内存溢出OOM 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 经典错误 JVM 中常见的两个 OOM 错误 StackoverflowError:栈溢出 ...
- 内存溢出(Oom)和内存泄露(Memory leak)
1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...
- 内存溢出(OOM)分析
当JVM内存不足时,会抛出java.lang.OutOfMemoryError. 主要的OOM类型右: Java heap space:堆空间不足 GC overhead limit exceed ...
- 在Android中解决内存溢出 – OutOfMemoryError
原文链接:http://riggaroo.co.za/fixing-memory-leaks-in-android-outofmemoryerror/ 注:本文在原文基础上在如何判断内存是否泄露方面进 ...
- bitmap 内存溢出OOM的解决办法分享
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...
- android 内存溢出oom错误的一些小见解
转:http://blog.csdn.net/xuhui_7810/article/details/9493681 我们在代码里调用setBackgroundResource(int resid)来设 ...
随机推荐
- UOJ 48 次最大公约数
次最大公约数 = gcd / 其中一个数质因数中最小的. gcd(42,12) = 6; div(42) = 2*3*7 div(12) = 2^2*3 sgcd(42,12) = 6 / ...
- POJ 2531 深搜剪枝
题意:全局最大割. 分析:有相应的算法,数据量很小,可以枚举源点,汇点,最大流. 这里用DFS,状态定义:分成两个集合,刚开始S集合全部点,然后一个一个放,这是一个回溯的过程. 没剪枝也过了. 剪枝技 ...
- Git错误
$ rm -rf .git $ git config --global core.autocrlf false $git init $git add . ---------------------- ...
- mysql substring_index()查询某个字符中以某个分割符分割后的值
substring_index(某个字段,以其分割,第几个分割点之前的值); +---------------------------------------------------------+ | ...
- 课时70.id选择器和类选择器(理解)
1.id和class的区别? id相当于人的身份证不可以重复 class相当于人的名称可以重复 1.2 一个HTML标签只能绑定一个id名称 一个HTML标签可以绑定多个class名称 2.id选择器 ...
- update、commit、trancate,delete
update 用于更新表的数据,使用方式为: update table_name set column_name=值 条件 顺便一提:date数据插入更新应该使用 to_date()格式转换函数例如: ...
- DB2表空间重定向恢复数据库实战
DB2的备份恢复有点坑,当源系统和目标系统的路径设置不同时,要手动进行重定向恢复,本文是我一次实战操作之后总结的过程,仅供参考. 一.发出重定向恢复命令 DB2 RESTORE DB TO " ...
- aes 加密,解密
Javaaes加密: package com.sh.auth.util; import java.security.InvalidKeyException; import java.security. ...
- POST和GET请求区别
最新博客站点:欢迎来访 1. 请求长度的限制 在HTTP协议中,从未规定GET/POST的请求长度限制,对于GET,对url的限制来源于浏览器或web服务器,浏览器和服务器限制了url的长度.因此,在 ...
- 正则表达式之——exec,match
刚开始接触正则,发现了一件有意思的事,我想要匹配正则,这下尴尬了- -,光知道正则表达式写法,并不知道正则如何才能获取匹配值. 慢慢摸索中... 找到答案!!! 正则匹配有两种方法: 一种是match ...