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)来设 ...
随机推荐
- js图片预览(一张图片预览)
核心思想:无论是一张图片上传还是多图上传,首先我们都需要先获得图片对象. 栗子: <inuput type="file" id="myfile" onch ...
- 【oracle使用笔记2】使用Oracle数据库遇到的若干问题总结
一. 关于Oracle 11g数据库在查询表中数据显示中文乱码问题 [描述]本人一开始使用的Oracle是11g版本的,用PLSQL一次查询表中的数据时出现了中文显示乱码,为此搜了许多解决办法,最终通 ...
- C#实现文件上传以及文件下载
public ActionResult Upload() { // var pathUrl = "http://" + Request.Url.Authority; var fil ...
- 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--I-填空题
链接:https://www.nowcoder.com/acm/contest/90/I 来源:牛客网 1.题目描述 牛客网是是一个专注于程序员的学习和成长的专业平台,集笔面试系统.课程教育.社群交流 ...
- linux链路聚合
配置聚合连接(网卡绑定,链路聚合): eth0 ================>>虚拟网卡team eth1 配置聚合连接 [root@Centos7-Server ~]# nmcli ...
- 【c学习-8】
/*继承结构体*/ #include // 定义子结构体 struct date{ int year; int month; int day; }; //定义父结构体 struct student{ ...
- Windows下安装Mysql5.5.27(社区版)
所有平台的 MySQL 下载地址为: MySQL 下载. 挑选你需要的 MySQL Community Server 版本及对应的平台. 运行mysql-5.5.27-win32.msi 进入欢迎界面 ...
- webBrowser 应用编程函数总结
/*============================说明部分================================= 实现一下函数需包含头文件 #include <Winine ...
- 微信小程序中无刷新修改
1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...
- phpstorm代码提示不小心关了,如何开启
在phpstrom右下角单击如图 出现event log窗口 如果不是 单击切换取消节电模式即可开启代码提示.