最近项目中用到了 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)问题的更多相关文章

  1. android解决内存溢出的问题(没有从根本上解决)

    Android游戏虚拟机算法JNI 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完 ...

  2. 内存溢出OOM与内存泄漏ML

    附, 微信团队原创分享:Android内存泄漏监控和优化技巧总结 一.如何避免OOM 异常 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中 ...

  3. 内存溢出OOM

    如何避免OOM 异常? 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang ...

  4. JVM:内存溢出OOM

    JVM:内存溢出OOM 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 经典错误 JVM 中常见的两个 OOM 错误 StackoverflowError:栈溢出 ...

  5. 内存溢出(Oom)和内存泄露(Memory leak)

    1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...

  6. 内存溢出(OOM)分析

    当JVM内存不足时,会抛出java.lang.OutOfMemoryError.   主要的OOM类型右: Java heap space:堆空间不足 GC overhead limit exceed ...

  7. 在Android中解决内存溢出 – OutOfMemoryError

    原文链接:http://riggaroo.co.za/fixing-memory-leaks-in-android-outofmemoryerror/ 注:本文在原文基础上在如何判断内存是否泄露方面进 ...

  8. bitmap 内存溢出OOM的解决办法分享

    昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...

  9. android 内存溢出oom错误的一些小见解

    转:http://blog.csdn.net/xuhui_7810/article/details/9493681 我们在代码里调用setBackgroundResource(int resid)来设 ...

随机推荐

  1. 动态规划(DP),Human Gene Functions

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1027 http://poj.org/problem?id=108 ...

  2. 【luogu P2661 信息传递】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2661#sub 一种利用并查集求最小环的做法: 对于每个同学看作一个点,每次信息传递是一条有向边,当出现最小环 ...

  3. 使用百度新闻RSS

    function getbaidu() { $result=""; //RSS源地址列表数组 $rssfeed = array("http://news.baidu.co ...

  4. video object detection

    先说一下,我觉得近两年最好的工作吧.其他的,我就不介绍了,因为我懂得少. 微软的jifeng dai的工作. Deep Feature Flow   github: https://github.co ...

  5. linux网络相关配制及命令

    1.虚拟机配制 查看ip: ip addr 配制网卡(读者可以忽略): 编辑虚拟网络编辑器,修改子网IP 查看ip,输入ip addr 开启网络:ifup eth0  关闭网络:ifdown eth0 ...

  6. css3 笔记

    1.元字符使用: []: 全部可选项 ||:并列 |:多选一 ?: 0个或者一个 *:0个或者多个 {}: 范围 2.CSS3属性选择器: E[attr]:存在attr属性即可: E[attr=val ...

  7. python写爬虫的弯路

    一开始按照视频上的找了笔趣阁的网站先爬一部小说, 找了<遮天>,但是章节太多,爬起来太慢, 就换了一个几十章的小说. 根据视频里的去写了代码, 在正则表达式哪里出了很大的问题. from ...

  8. chromium之tracked

    //------------------------------------------------------------------------------ // Tracked is the b ...

  9. ansible-palybook剧本

    1 ansible基础知识部分补充 1.1 ansible软件特点: · 可以实现批量管理 · 可以实现批量部署 · ad-hoc(批量执行命令)---针对临时性的操作 ansible clsn -m ...

  10. node-zookeeper-dubbo 和egg实现远程连接

    基于js的node-zookeeper-dubbo 和egg实现远程连接服务 const nzd = require('node-zookeeper-dubbo'); const opt={ appl ...