3

I've had a specific issue when running some basic code on a Samsung Galaxy S4 (model: GT-I9500).

I was implementing a image picker via the camera or gallery, and could not for the life of me figure out why the ImageView was blank when calling -

imageView.setImageURI(uri);

It wasn't until I ran the exact same code in the emulator (and then a Nexus 5) that I found that this was a Samsung S4 issue.

Full sample project can be found on Github & ready to run

Code I used was taken from this SO post:

In OnCreate:

btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("Choose Image Source");
            builder.setItems(new CharSequence[]{"Gallery", "Camera"},
                    new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            switch (which) {
                                case 0:

                                    //Launching the gallery
                                    Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                                    startActivityForResult(i, GALLERY);

                                    break;

                                case 1:
                                    //Specify a camera intent
                                    Intent getCameraImage = new Intent("android.media.action.IMAGE_CAPTURE");

                                    File cameraFolder;

                                    //Check to see if there is an SD card mounted
                                    if (android.os.Environment.getExternalStorageState().equals
                                            (android.os.Environment.MEDIA_MOUNTED))
                                        cameraFolder = new File(android.os.Environment.getExternalStorageDirectory(),
                                                IMAGEFOLDER);
                                    else
                                        cameraFolder = MainActivity.this.getCacheDir();
                                    if (!cameraFolder.exists())
                                        cameraFolder.mkdirs();

                                    //Appending timestamp to "picture_"
                                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
                                    String timeStamp = dateFormat.format(new Date());
                                    String imageFileName = "picture_" + timeStamp + ".jpg";

                                    File photo = new File(Environment.getExternalStorageDirectory(),
                                            IMAGEFOLDER + imageFileName);
                                    getCameraImage.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));

                                    //Setting a global variable to be used in the OnActivityResult
                                    imageURI = Uri.fromFile(photo);

                                    startActivityForResult(getCameraImage, CAMERA);

                                    break;
                                default:
                                    break;
                            }
                        }
                    });

            builder.show();
        }
    });

OnActivityResult:

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

    if (resultCode == RESULT_OK) {


        switch (requestCode) {
            case GALLERY:
                Uri selectedImage = data.getData();
                imageView.setImageURI(selectedImage);

                break;
            case CAMERA:

                imageView.setImageURI(imageURI);
                break;
        }

    }

}

Also occurs when using Picasso

 if (resultCode == RESULT_OK) {


        switch (requestCode) {
            case GALLERY:
                Uri selectedImage = data.getData();
                Picasso.with(context)
                        .load(selectedImage)
                        .into(imageView);

                break;
            case CAMERA:
                Picasso.with(context)
                        .load(imageURI)
                        .into(imageView);
                break;
        }

    }

Also occurs when using Bitmap Factory

  try {
                    Bitmap bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(imageURI));
                    imageView.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }

enter image description here

The results when ran on a Samsung S4 running 4.2.2

S4 Before S4 After

The results when ran on a GenyMotion 2.4.0 running Android 4.4.4

GenyMotion Before GenyMotion After

Anyone know why this happens?

Community
  • 1
  • 1
AJ9
  • 1,256
  • 1
  • 17
  • 28
  • `setImageURI()` is rarely a good idea, as that will load the image on the main application thread. – CommonsWare Apr 29 '15 at 00:05
  • What would a better solution be when loading an image from the Gallery? – AJ9 Apr 29 '15 at 00:07
  • Use one of the [many image loading libraries](https://android-arsenal.com/tag/46) that will load the image on a background thread and apply it to the `ImageView` when ready. Or, do that yourself, perhaps using an `AsyncTask`. – CommonsWare Apr 29 '15 at 00:12
  • 1
    So I tried using Picasso, but that doesn't work either. It still loads a blank imageview. I'll add that to the github repo. – AJ9 Apr 29 '15 at 00:14
  • Well, that's a little strange. Does this happen for all images that you are pulling from the `MediaStore`, or only some? – CommonsWare Apr 29 '15 at 00:16
  • All images. And it's only for the Samsung S4. It works fine (using the above method and Picasso) in a Nexus 5, a cheap Android tablet, GenyMotion and the built in Android emulator. – AJ9 Apr 29 '15 at 00:19
  • It happens for both the Gallery and Camera pictures too. – AJ9 Apr 29 '15 at 00:20
  • There are a few models known as the Galaxy S4 (GT-I9500, SGH-I337, etc.). Which is yours? – CommonsWare Apr 29 '15 at 00:21
  • The model I have is - GT-I9500 – AJ9 Apr 29 '15 at 00:25
  • Hmmm... mine is running 4.3, not 4.2.2. Still, I may try to reproduce your problem. – CommonsWare Apr 29 '15 at 00:28
  • @AJ9 were you able to fix this issue? – Aniruddha K.M Nov 04 '16 at 14:14

3 Answers3

3

So the problem turns out to be the image bitmaps being too large for the Samsung S4 to handle.

Frustratingly no errors are thrown - The correct solution is as follows:

switch (requestCode) {
            case GALLERY:
                Bitmap bitmap = createScaledBitmap(getImagePath(data, getApplicationContext()), imageView.getWidth(), imageView.getHeight());
                imageView.setImageBitmap(bitmap);
                break;
            case CAMERA:
                String path = imageURI.getPath();
                Bitmap bitmapCamera = createScaledBitmap(path, imageView.getWidth(), imageView.getHeight());
                imageView.setImageBitmap(bitmapCamera);
                break;
        }

Helper methods:

// Function to get image path from ImagePicker
public static String getImagePath(Intent data, Context context) {
    Uri selectedImage = data.getData();
    String[] filePathColumn = {MediaStore.Images.Media.DATA};
    Cursor cursor = context.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
    cursor.moveToFirst();
    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String picturePath = cursor.getString(columnIndex);
    cursor.close();
    return picturePath;
}


public Bitmap createScaledBitmap(String pathName, int width, int height) {
    final BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(pathName, opt);
    opt.inSampleSize = calculateBmpSampleSize(opt, width, height);
    opt.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(pathName, opt);
}

public int calculateBmpSampleSize(BitmapFactory.Options opt, int width, int height) {
    final int outHeight = opt.outHeight;
    final int outWidth = opt.outWidth;
    int sampleSize = 1;
    if (outHeight > height || outWidth > width) {
        final int heightRatio = Math.round((float) outHeight / (float) height);
        final int widthRatio = Math.round((float) outWidth / (float) width);
        sampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return sampleSize;
}
AJ9
  • 1,256
  • 1
  • 17
  • 28
  • I am glad that you got things basically working. However, your "Function to get image path from ImagePicker" will not work reliably, particularly on newer Android devices. As I seem to keep saying, [a `Uri` is not a file](https://commonsware.com/blog/2014/07/04/uri-not-necessarily-file.html). Moreover, you do not need it. Simply use `getContentResolver().openInputStream()`, then use `decodeStream()` on `BitmapFactory`. – CommonsWare Apr 29 '15 at 20:52
1

When using Picasso, use fit() or resize(). It handles resizing the bitmap.

iamstuffed
  • 74
  • 2
0

Are they using different apps by any chance? 4.4 introduced several new URIs for image selecting, as they can be local, google plus etc.

Try this: BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))

It returns a Bitmap that can be used in the image view as

imgView.setImageBitmap(bitmap)
Ryan
  • 1,863
  • 13
  • 20
  • They're exactly the same apps, pushed from exactly the same IDE/set up. I also tried the above which didn't work, I'll add a third activity to the project and more screenshots later today. – AJ9 Apr 29 '15 at 08:06
  • Doesn't work: https://github.com/AJ9/Samsung-S4-ImageView-Test/blob/master/README.md#solutions-tried – AJ9 Apr 29 '15 at 10:23