1

I have an app that allow user to upload a photo on wall.

The code works well for the majority of users, but I have reported that the application crashes sometimes when uploading photo.

The problem is not in taking the pictures from the camera, but it is when you have to take the path of the picture.

The version of Android that is causing this problem is 4.4.2, but I do not understand how to fix it.

post some code:

activityResult:

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

    if (resultCode == RESULT_OK) {

        if (requestCode == CAMERA_PIC_REQUEST) {

            try {
                //picUri is a global variable Uri
                picUri = data.getData();

                cropImage();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        else if(requestCode == PIC_CROP) {

            try{
                //thumbnail is a global variable Bitmap
                thumbnail = MediaStore.Images.Media.getBitmap(context.getContentResolver(), cropImageUri);

                setImage();
            }
            catch (Exception e) {

                e.printStackTrace();
            }

        }
    }
}

hot to crop image:

public void cropImage() {

    try {

        Intent cropIntent = new Intent("com.android.camera.action.CROP");
        //indicate image type and Uri
        cropIntent.setDataAndType(picUri, "image/*");
        //set crop properties
        cropIntent.putExtra("crop", "true");
        //indicate aspect of desired crop
        cropIntent.putExtra("aspectX", 1);
        cropIntent.putExtra("aspectY", 1);
        cropIntent.putExtra("scale", true);
        //indicate output X and Y
        cropIntent.putExtra("outputX", 700);
        cropIntent.putExtra("outputY", 700);
        //retrieve data on return
        cropIntent.putExtra("return-data", false);

        File f = createNewFile("CROP_");
        try{
            f.createNewFile();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        //cropImageUri is a global variable Uri
        cropImageUri = Uri.fromFile(f);


        cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);

        //start the activity - we handle returning in onActivityResult
        startActivityForResult(cropIntent, PIC_CROP);
    }
    catch(ActivityNotFoundException anfe){

        anfe.printStackTrace();
    }
}

create new File:

private File createNewFile(String prefix) {

    if (prefix== null) {
        prefix="IMG_";
    }
    else if("".equalsIgnoreCase(prefix)) {
        prefix="IMG_";
    }

    File newDirectory = new File(Environment.getExternalStorageDirectory()+"/mypics/");
    if (!newDirectory.exists()) {
        if (newDirectory.mkdir()) {

        }
    }

    File file = new File(newDirectory,(prefix+System.currentTimeMillis()+".jpg"));
    if (file.exists()) {
        file.delete();
        try {
            file.createNewFile();
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    return file;
}

then when a user click on "send" method preUploadImage is called:

public void preUploadImage() {

    UploadImage uploadImage = new UploadImage();

    Uri newUri = getImageUri(thumbnail);

    try{
        //   System.out.println("uri = "+picUri);
        uploadImage.upload(getRealPathFromURI(newUri));

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

public Uri getImageUri(Bitmap inImage) {

    String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "Title", null);

    return Uri.parse(path);
}

and in the last row the error appears.

return Uri.parse(path); 

this row cause a NullPointerException

java.lang.NullPointerException: uriString
at android.net.Uri$StringUri.<init>(Uri.java:468)
at android.net.Uri$StringUri.<init>(Uri.java:458)
at android.net.Uri.parse(Uri.java:430)
at com.delsorboilario.verdebio.ScriviDomanda.getImageUri(ScriviDomanda.java:584)
at com.delsorboilario.verdebio.ScriviDomanda.preUploadImage(ScriviDomanda.java:608)
at com.delsorboilario.verdebio.ScriviDomanda$6$4$2.run(ScriviDomanda.java:292)
Ilario
  • 5,979
  • 2
  • 32
  • 46
  • First, [Android does not have a `CROP` `Intent`](http://commonsware.com/blog/2013/01/23/no-android-does-not-have-crop-intent.html). Second, [a `Uri` is not necessarily a file](http://commonsware.com/blog/2014/07/04/uri-not-necessarily-file.html). – CommonsWare Feb 05 '15 at 12:38
  • @CommonsWare oh thanks.. I never had problems with this intent .. I'll try to use the libraries that are in the article. now you have any suggestion to solve my problem? thanks – Ilario Feb 05 '15 at 12:44
  • I have never attempted to use `insertImage()`. If I want to write a file to external storage, I write a file to external storage, then use `MediaScannerConnection` and `scanFile()` to get the image indexed by `MediaStore`. – CommonsWare Feb 05 '15 at 12:48
  • @CommonsWare and how you write a file to external storage? – Ilario Feb 05 '15 at 12:58
  • Through standard Java file I/O, using appropriate methods to get at a root location, such as `getExternalFilesDir()` on `Context` or `getExternalStoragePublicDirectory()` on `Environment`. – CommonsWare Feb 05 '15 at 12:59
  • @CommonsWare sorry man but can you tell me if you do something different from my method: private File createNewFile (String prefix)? – Ilario Feb 05 '15 at 13:01
  • There's nothing especially wrong with that, other than cluttering up the user's external storage with a random directory. You are better served using `getExternalFilesDir()`, particularly if the images should not remain on the device after your app is uninstalled. But then, at this point, you know the path to the image, because **you created the path to the image**. You can upload using that `File` object, rather than messing around with obsolete `getRealPathFromURI()` stuff. – CommonsWare Feb 05 '15 at 13:04
  • @CommonsWare thanks for your time, but you can show me how to use MediaScannerConnection instead insertImage(); ? – Ilario Feb 05 '15 at 13:07
  • Um, it's a static method. You just call it. Here is a blog post describing why we need to get files indexed by `MediaStore` in general: http://commonsware.com/blog/2011/08/31/mtp-external-storage.html Here is a Stack Overflow answer showing the use of `scanFile()`: http://stackoverflow.com/a/21874207/115145 – CommonsWare Feb 05 '15 at 13:17
  • @CommonsWare i'm trying... for now thats work, but to be sure I have to try on a Android 4.4. i'll let you know.. thanks! – Ilario Feb 05 '15 at 13:46
  • @CommonsWare thanks man! works on Android 4.4 too! if you leave an answer I will be happy to accept it. ;) – Ilario Feb 05 '15 at 18:44

2 Answers2

2

Looks like MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "Title", null); return null.

Form the documentation of MediaStore.Images.Media

Insert an image and create a thumbnail for it.

Parameters

cr The content resolver to use

source The stream to use for the image

title The name of the image

description The description of the image

Returns The URL to the newly created image, or null if the image failed to be stored for any reason

Jens
  • 67,715
  • 15
  • 98
  • 113
  • yes but why only in some version of Android?? and how fix it? ... so the problem is to store image? – Ilario Feb 05 '15 at 12:06
  • @Ilario Yes the problem is storing the image. – Jens Feb 05 '15 at 12:09
  • @Ilario Look [here](http://stackoverflow.com/questions/12230942/why-images-media-insertimage-return-null) – Jens Feb 05 '15 at 12:12
  • the firs answer is pretty useless ... the last instead looks promising, but how do I create the directory mentioned? – Ilario Feb 05 '15 at 12:14
  • Using a `File` object?! – Jens Feb 05 '15 at 12:20
  • its ok... but where? replace: new File (Environment.getExternalStorageDirectory () + "/ mypics /"); with: new File (Environment.getExternalStorageDirectory () + "/ sdcard / DCIM / Camera /"); ?? – Ilario Feb 05 '15 at 12:24
2

I have not attempted to use insertImage(), and in this case, it is not quite clear why you would need it.

Primarily, it seems like you are looking to upload the photo. For that, all you need is the File that you created in createNewFile(). If you are uploading it yourself (e.g., HttpUrlConnection, some third-party library), you should be able to just use the File or an InputStream on it. Even if the upload code really needs a Uri, you can try Uri.fromFile() to get a Uri from your File and see if that works.

Where MediaStore does come into play is making your file be indexed and therefore accessible to apps (ones that query the MediaStore for images) and to users (via their MTP connection through their USB cable). MediaScannerConnection and its static scanFile() method are a fairly straightforward way to get the file indexed. Just make sure your file is fully written to disk first (e.g., if you are writing the file yourself, call getFD().sync() on your FileOutputStream after flush() and before close()).

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491