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)来设 ...
随机推荐
- 记忆化搜索,FatMouse and Cheese
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1107 http://acm.hdu.edu.cn/showpro ...
- 【[SDOi2012]Longge的问题】
求\(\sum_{i=1}^ngcd(i,n)\) 考虑枚举\(gcd\),现在答案变成这样 \(\sum_{d|n}d*f(d)\) \(f(d)=\sum_{i=1}^n [gcd(i,n)==d ...
- 更改win7关机菜单选项功能
说明:如果你不希望别人对你的电脑进行注销切换等操,那么可以使用如下的方法 实现效果: 实现步骤: 效果1 1>切换用户: 2>注销:(需重启资源管理器生效) 效果2:
- idea 一次性自动导包
当复制粘贴一段纯文本代码时,许多类需要导包. 如图 使用optimize imports了,发还是没有办法导入未导入的包,只能删除未使用导包,这跟eclipse不一样,让人很不习惯,查了好多资料都没有 ...
- C#中对于float,double,decimal的误解(转载)
浮点型 Name CTS Type Description Significant Figures Range (approximate) float System.Single 32-bit sin ...
- AngularJS 使用 uppercase 过滤器的表格
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- Android 初步-Android文件目录介绍
src:存放的是应用程序使用到的java文件. gen:系统自动生成的目录,不需要程序员进行修改,包含了R.java文件.该文件包含了 程序使用到的资源文件对应的唯一资源ID,注意:如果R文件生成错误 ...
- Mysql jar包
密码cngb https://pan.baidu.com/share/init?surl=bSGA6T-LTwjx-qaNAiipCA
- iOS之苹果调整 App Store 截图上传规则,截图尺寸、大小等
作者:ASO100链接:https://zhuanlan.zhihu.com/p/23041522来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 自从 8 月中旬苹果向 ...
- Git工作流指南:Gitflow工作流
git工作流 1.Git flow 核心分支:master,dev 可能还会有:功能分支,bug修复分支,预发布分支 2.github flow:只一个长期分支,就是master 第一步:根据需求,从 ...