2

I have an app where the user picks an image from either the cloud, internal storage or external storage. The app then saves the image to the device and then stores the file path to a sqlite database. It then later uses the Picasso library to load the image from the file path. My problem is that when it goes to load the image from the file path, it loads it extremely slow. After saving the image, it takes maybe a minute to finally display it.

My question is: What is the most efficient way to save and load images chosen by a user. I would like it to load the images faster.

Here is my code:

Method that gets the result of the Intent for user to choose image

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) 
    {

        if(requestCode == 1)
        {
            try {
                if (bitmap != null)
                {
                    bitmap.recycle();
                }

                InputStream stream = getContentResolver().openInputStream(data.getData());
                bitmap = BitmapFactory.decodeStream(stream);
                stream.close();

                Picasso.with(getBaseContext()).load(data.getData()).fit().centerInside().into(imageButton);
                imageButton.setBackground(null);

            } 
            catch (FileNotFoundException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        pictureSelected = true;

        SaveImageTask saveBitmap = new SaveImageTask(bitmap);
        saveBitmap.execute();

    }
}

Async Task to do the image saving

    private class SaveImageTask extends AsyncTask<Void, Integer, Boolean> {

    private Bitmap bitmap;

    SaveImageTask(Bitmap bitmap) {
        this.bitmap = bitmap;
    }

    @Override
    protected Boolean doInBackground(Void...params) {

        // Create a media file name
        Calendar c = Calendar.getInstance();
        String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(c.getTime());
        String mImageName = "MT_"+ timeStamp +".jpg";
        String albumName = "My App";

        File file = null;

        String state = Environment.getExternalStorageState();

        // If there is external storage, save it in the pictures album. If not, save on internal storage
        if(Environment.MEDIA_MOUNTED.equals(state))
        {
            file = new File(addEdit.this.getExternalFilesDir(
                    Environment.DIRECTORY_PICTURES), albumName);
            if(!file.mkdirs())
            {
                file = new File(addEdit.this.getFilesDir(), mImageName);
            }
        }
        else
        {
            file = new File(addEdit.this.getFilesDir(), mImageName);
        }


        OutputStream fOut = null;
        try {
            fOut = new FileOutputStream(file);
            fOut.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        try {
            FileOutputStream fos = new FileOutputStream(file);
            filePath = file.getAbsolutePath();
            Log.v("Filepath", filePath);
            bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.close();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
            return false;
        }
        catch(IOException e)
        {
            e.printStackTrace();
            return false;
        }


        return true;

     }

     protected void onProgressUpdate(Integer... progress) {
     }

     protected void onPostExecute(Boolean success) {
     }

 }

How I load the file path

if(person.getImage() != null)
    {
        //convert byte to bitmap take from contact class
        File imgFile = new File (person.getImage());
        if(imgFile.exists())
        {
            Picasso.with(getBaseContext()).load(imgFile).fit().centerInside().into(imageView);
        }
    }

Any advice would be greatly appreciated. Thank you.

Sloganho
  • 2,041
  • 3
  • 16
  • 20
  • Just wondering why do you want to store it to the local memory? – Sharjeel Jan 15 '15 at 16:05
  • I just want to store it anywhere on the device so that I can easily access it later. The user saves the image as a "profile picture" essentially. I'm just asking how to do it more efficiently so if storing it on local memory isn't efficient, I'm trying to find the better alternative. @Sharj – Sloganho Jan 15 '15 at 16:10
  • http://www.captechconsulting.com/blog/raymond-robinson/google-io-2013-volley-image-cache-tutorial – Robert Rowntree Jan 15 '15 at 16:11
  • https://github.com/bumptech/glide – Robert Rowntree Jan 15 '15 at 16:19
  • Maybe in your case you have to store image, but normally we don't store images. Like you are using Picasso, it has automatic caching implemented. When you try to show image 2nd time it will show from caching instead of downloading from the internet. This library has even advanced caching options https://github.com/nostra13/Android-Universal-Image-Loader – Sharjeel Jan 15 '15 at 16:24
  • In my case I do need to store my image because I don't do anything client side. The user would need to store the image so that when they open the app a month from now, they can still see the image that they chose. You're right, Picasso does automatic caching. After more research I have found that it's not the image loading that is having the problem. It's storing the image that is taking so long. I'll read up more on the android.developers site to know the best practice for that. Thank you. – Sloganho Jan 15 '15 at 17:07

1 Answers1

1

one option would be to cache image thorugh WeakRefrence in that way you can keep image in memory and if image is not in memory then load from sdcard

i think below links can help you

weakReference and other weak reference for cache

Community
  • 1
  • 1
Moubeen Farooq Khan
  • 2,875
  • 1
  • 11
  • 26
  • According to the android.devlopers site, this is not recommended "Note: In the past, a popular memory cache implementation was a SoftReference or WeakReference bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash." – Sloganho Jan 15 '15 at 16:31
  • see [link](http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html) – Sloganho Jan 15 '15 at 16:32