zoukankan      html  css  js  c++  java
  • Android ImageSwitcher 配合Picasso解决内存溢出(OOM)问题

    最近项目中用到了 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问题,但滑动时的效果没有了,后续再优化。

  • 相关阅读:
    关于eclipse 的 web.xml文件 There is '1' error in 'j2ee_1_4.xsd'. 错误
    C#实现Java的AES加密解密算法
    jsp页面报错javax.servlet.jsp.jspException cannot be resolved to a type
    Ubuntu下查看jdk安装路径
    【Mysql】启动mysql报错mysqld_safe error: log-error set to /var/log/mariadb/mariadb.log
    spring mvc导出csv案例
    MyBatis 调用存储过程(详解)
    mysql 无限递归出现 data too long for column 'xxx' 错误
    java的maven项目头上有红叉解决方法
    Nexus3搭建Docker等私服
  • 原文地址:https://www.cnblogs.com/lurenjiashuo/p/android-ImageSwitcher-picasso-oom-crash.html
Copyright © 2011-2022 走看看