最近项目中用到了 ImageSwitcher 来实现图片切换,使用起来很简单,但发现当图片比较大(超过了3M)时,程序出现了内存溢出(OOM)问题而崩溃了。

原因就是图片太大了,显示到 ImageView 上时,内存不够用了。而业界有几个很出名的图片库已经解决了加载大图片内存溢出问题,其中比较出名的就有 square 公司开发的 picasso 和 bumptech 开发的 Glide ,这两个库都很优秀,各有长处(关于这两个库的比较,请参考:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html)。

那么如何让 ImageSwitcherPicasso 配合使用呢?

布局上,只要让 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. js图片预览(一张图片预览)

    核心思想:无论是一张图片上传还是多图上传,首先我们都需要先获得图片对象. 栗子: <inuput type="file" id="myfile" onch ...

  2. 【oracle使用笔记2】使用Oracle数据库遇到的若干问题总结

    一. 关于Oracle 11g数据库在查询表中数据显示中文乱码问题 [描述]本人一开始使用的Oracle是11g版本的,用PLSQL一次查询表中的数据时出现了中文显示乱码,为此搜了许多解决办法,最终通 ...

  3. C#实现文件上传以及文件下载

    public ActionResult Upload() { // var pathUrl = "http://" + Request.Url.Authority; var fil ...

  4. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--I-填空题

    链接:https://www.nowcoder.com/acm/contest/90/I 来源:牛客网 1.题目描述 牛客网是是一个专注于程序员的学习和成长的专业平台,集笔面试系统.课程教育.社群交流 ...

  5. linux链路聚合

    配置聚合连接(网卡绑定,链路聚合): eth0 ================>>虚拟网卡team eth1 配置聚合连接 [root@Centos7-Server ~]# nmcli ...

  6. 【c学习-8】

    /*继承结构体*/ #include // 定义子结构体 struct date{ int year; int month; int day; }; //定义父结构体 struct student{ ...

  7. Windows下安装Mysql5.5.27(社区版)

    所有平台的 MySQL 下载地址为: MySQL 下载. 挑选你需要的 MySQL Community Server 版本及对应的平台. 运行mysql-5.5.27-win32.msi 进入欢迎界面 ...

  8. webBrowser 应用编程函数总结

    /*============================说明部分================================= 实现一下函数需包含头文件 #include <Winine ...

  9. 微信小程序中无刷新修改

    1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...

  10. phpstorm代码提示不小心关了,如何开启

    在phpstrom右下角单击如图 ​ 出现event log窗口 ​ 如果不是​ 单击切换取消节电模式即可开启代码提示.