Android ImageSwitcher cooperates with Picasso to solve memory overflow (OOM) problem

Recently, ImageSwitcher was used in the project to switch between images. It is very simple to use, but it was found that when the image size was large (more than 3M), the program crashed due to memory overflow (OOM).

The reason is that the picture is too large, and when it is displayed on ImageView, the memory is not enough. However, there are several well-known image libraries in the industry that have solved the problem of memory overflow when loading large images. Among them, picasso developed by square company and Glide developed by bumptech are more famous. These two libraries are excellent and have their own advantages (about For a comparison of these two libraries, please refer to: http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html).

So how to make ImageSwitcher work with Picasso?

In terms of layout, just make the background of ImageSwitcher transparent, then put an ImageView behind it, and then use ImageSwitcher to make left and right sliding effects, and then The actual display of the picture uses the ImageView behind it.

The layout is as follows:

<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>

About how to use Picasso, I won’t say much here, please refer to the official instructions. There are two points to note here:
1. makeView in the implementation of ImageSwitcher should be set as a transparent background
2. Picasso needs to call fit() and centerCrop() to adjust the image size, thus greatly saving memory

The key code is as follows:

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 = "The path of the folder where the picture is located";
        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: {
                //The X coordinate of the finger pressed
                mDownX = event. getX();
                break;
            }
            case MotionEvent. ACTION_UP: {
                float lastX = event. getX();
                //When the X coordinate is greater than when it is lifted, it will display the previous picture
                if (lastX > mDownX) {
                    if (mCurrentPosition > 0) {
                        // set animation
                        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);
            }
        }
    }
}

Note: Some logic codes that are not relevant to this article have been removed.

The usage part of ImageSwitcher refers to: http://blog.csdn.net/xiaanming/article/details/8988152

At present, this solution can solve the OOM problem, but the effect of sliding is gone, and it will be optimized later.