4

In AddMoreClaims Activity , there has an imageView, button and save button.

When button is clicked, it will goes to activeGallery() and let user select image from gallery. The selected image will then display on imageView AddMoreClaims.

  private void activeGallery() {
        Intent intent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(intent, RESULT_LOAD_IMAGE);
    }

 @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case RESULT_LOAD_IMAGE:
                if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK & null != data) {
                    Uri selectedImage = data.getData();
                    String[] filePathColumn = {MediaStore.Images.Media.DATA};
                    Cursor cursor = getContentResolver()
                            .query(selectedImage, filePathColumn, null, null,
                                    null);
                    cursor.moveToFirst();
                    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                    String picturePath = cursor.getString(columnIndex);
                    cursor.close();
                    photo = decodeSampledBitmapFromUri(picturePath,200,200); // make image clear
                    imageView.setImageBitmap(photo); // display image on imageView
                }
                break;
}

 public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth,
                                             int reqHeight) {

        Bitmap bm = null;
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        bm = BitmapFactory.decodeFile(path, options);
        return bm;
    }

    public int calculateInSampleSize(

            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2
            // and keeps both height and width larger than the requested
            // height and width.
            while ((halfHeight / inSampleSize) > reqHeight &&
                    (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
}

In order to make sure the image selected placed on the imageView is clear, I have added decodeSampledBitmapFromUri(picturePath,200,200). So far everything works fine.

When save button is clicked, it supposes return the image to AddClaims listView.

 saveBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent returnIntent = new Intent(); // back to AddClaims
                returnIntent.putExtra("photo", photo);
                setResult(Activity.RESULT_OK, returnIntent);
                finish();

            }
        });

However, the above coding does not worked sometimes. I'm not sure isin't because the image selected too big , when I click the save button and want to return the image to listView AddClaims, it just return to the activity before AddClaims. . But the code works for some selected image. Why would this happen ?

  • 3
    Check your logcat for exceptions/errors. – Buddy Dec 16 '15 at 15:08
  • @Buddy the app does not crashed. Do you know how can I check the selected image size ? Is it because the size too big? –  Dec 16 '15 at 15:14
  • Could be that it sometimes is to big. It will happen again if your image couldn't be loaded into memory => next activity chrashes => goes back to previous. Try scaling you image... (scaling isn't like making the iidth and height smaller ) – SamuelD Dec 16 '15 at 15:45
  • @SamuelD did you mean something like `photo = scaleBitmap(a, 200, 200);` ? I try this function and it works, but it make the image on `imageView` looked blur.. –  Dec 16 '15 at 15:49
  • Yes, look into this http://stackoverflow.com/questions/4821488/bad-image-quality-after-resizing-scaling-bitmap It is using another option = inscaled() and maybe this to keep aspect ratio: http://developer.android.com/reference/android/widget/ImageView.html – SamuelD Dec 16 '15 at 15:55
  • @SamuelD can you check my code again? (Scale image code) Where should I add `option = inscaled()` ? –  Dec 16 '15 at 16:07
  • Replace the line in decodeSampledBitmapFromUri() with the one i gave you .. Any Success ? – SamuelD Dec 17 '15 at 08:14
  • see http://stackoverflow.com/questions/34317607/scale-image-without-losing-image-quality-did-not-work –  Dec 17 '15 at 08:22

4 Answers4

2

Its not a good way to pass image via return intent. try writing it to sd card, access from other screen.(then delete it if its confidential)

An image bitmap usually have a size range of 18MB+...So depending upon Heap availability and all it may or may not work. Even in high end devices this may occur due to unavailability of space in Heap. Or you can clear unwanted items from heap in a programmatic way before doing this.

shijin
  • 2,998
  • 1
  • 24
  • 30
  • If I write it to sd card, how can I get the image back when return to previous activity ? –  Dec 22 '15 at 01:19
  • @Seng pass the path of files via Intents, not the file itself. Otherwise the application will behave differently depending on the file size. It's not confirmed, but usually more than 1MB is not handled via intents (usually an exception is thrown). – fasteque Dec 25 '15 at 10:09
  • @Seng you can get the image from the same path you writed. Better check this sample. Its pretty old. but i think it will do. http://developer.android.com/shareables/training/PhotoIntentActivity.zip – shijin Dec 26 '15 at 05:54
2

First, it is preferable to decode your bitmaps asynchroniously, not on the UI thread. Second, do not pass bitmaps via intents. There is also no need to write anything on the sd card since the image is already on your device.

I recommend you to use an image loading library - you can see some of the best listed here.

Those libraries' main purpose is to download, cache and display images from the internet, but they also work great for displaying images from the local storage.

For example, if you choose Picasso, your code will be something like this:

Picasso.with(this) 
    .load(new File(picturePath)) 
    .resize(yourTargetWidth, yourTargetHeight)
    .centerInside() 
    .into(imageView);

As you can see, the library generates, crops and displays the bitmap for you.

When your button is clicked, you can pass picturePath to your other Activity via Intet, where you can display the image using the same approach - Picasso.with(this)...

tochkov
  • 2,917
  • 2
  • 15
  • 21
0

You should follow these practice to avoid OOM exceptions:

  1. All the bitmap operations should be done on a worker thread. http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
  2. After processing, create cache of bitmap using bitmap file path.
  3. Pass this bitmap file path via intent to another activity.
  4. In new activity, get bitmap from cache using supplied file path.

For bitmap caching, you can use any of the below libraries:

http://square.github.io/picasso/

https://github.com/bumptech/glide

https://github.com/nostra13/Android-Universal-Image-Loader

Geeky Singh
  • 1,003
  • 9
  • 20
  • you may add this one also, to complete the group https://github.com/facebook/fresco – MBH Dec 28 '15 at 15:06
0

For playing with Bitmap we have to optimize our code as much as we can. Either we have to give time for that or can use Image Loading Libraries which are much optimized already. I used Picaso in my project. It will take care of image size and will return selected image bitmap. I used this code for getting image from library and it work like charm.

Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, REQUEST_TAKE_GALLERY);

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            if (requestCode == REQUEST_TAKE_GALLERY) {
                    Uri selectedImage = data.getData();
                    String[] filePath = {MediaStore.Images.Media.DATA};
                    Cursor c = getContentResolver().query(selectedImage, filePath, null, null, null);
                    c.moveToFirst();
                    int columnIndex = c.getColumnIndex(filePath[0]);
                    String picturePath = c.getString(columnIndex);

                    c.close();
                    Bitmap thumbnail = (BitmapFactory.decodeFile(picturePath));
                    Log.e("path of image from gallery......******************.........", picturePath + "");

                    Picasso.with(mContext).load(new File(picturePath)).fit().centerCrop().memoryPolicy(MemoryPolicy.NO_CACHE).into(mProfilePic);    //Here mContext is context of Screen Context mContext;         
                }
            }
        }

When you need to send selected image to other activity. You can check this link.

https://stackoverflow.com/a/11010565/2022000

Community
  • 1
  • 1
Anuj Sharma
  • 4,294
  • 2
  • 37
  • 53
  • CommonMethods,Picasso.with(mContext),Memorypolicy cannot be resolved –  Dec 30 '15 at 03:33
  • ComonMethods is my custom class where i wrote all methods, You can use Log.e("","to display result"); and mContext in Picaso is context of activity. You can write YourActivityName.this instead of that. – Anuj Sharma Dec 30 '15 at 04:40