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问题,但滑动时的效果没有了,后续再优化。

posted @ 2016-02-25 16:44  观海云不远  阅读(1034)  评论(0编辑  收藏  举报