0

UPDATE2: The problem has to do with onResume and onPause. It has nothing to do with the BitmapFactory.decodeFile(). The problem is that when I go to take the picture, onPause is called, but nothing is saved to SharedPreferences, since there is not yet anything to be saved. But once I return from taking the picture, onResume is called and attempts to set the image path to the custom object by taking the appropriate value from SharedPreferences. Since there is no corresponding value there, it applies the default value of null to imagePath.

UPDATE: The layout of my program is ActivityA hosts FragmentA which hosts this DialogFragment you see below. The user presses a button in FragmentA to take a picture, and once they have taken the picture, in onActivityResult I set the image path as a String variable in a custom object, and I verify it exists by calling Log.d(mObject.getImagePath(), ...).

They can then re-press the same picture button to view the image. This is where the NullPointerException occurs. Although I verify that the image path exists in onActivityResult, it returns null later when I try to access it. This is why the BitmapFactory.decodeFile() returns null- since imagePath is null in FragmentA, of course it will be null when I try to access it as an extra in DialogFragment.

Can anyone see why the image path is returning null, even when I verify it exists in onActivityResult and assign it to my object? I have no idea why this happens. I have a similar button where a user can input text, and then press the button again to view/edit that text in a dialog. I follow the same procedure of assigning the variable to my object in onActivityResult, and I have no problems.

NOTE: If you would like to see how the picture is taken and saved, please refer to this answer, or follow the linked question to the right.

imagePath:

/data/data/myPackageName/files/myInternalPicturesDir/IMG_20141011_152840.jpg.

FragmentA:

    //onCreateView
    mImageButton = (Button) v.findViewById(R.id.imageButton);
    mImageButton.setOnClickListener(new View.OnClickListener()
    {
        public void onClick(View v)
        {
            if (isImageButtonFirstClick)
            {
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                imageUri = CameraUtils.getOutputMediaFileUri(CameraUtils.MEDIA_TYPE_IMAGE);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, REQUEST_IMAGE);
            }
            else
            {
                try
                {
                    Log.d("mImageButton onClick", mMyObject.getImagePath());
                    //returns null...
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }

                FragmentManager fm = getActivity().getSupportFragmentManager();
                InputImageFragment dialog = InputImageFragment.newInstance(mMyObject.getImagePath());
                dialog.show(fm, DIALOG_IMAGE);
            }
        }
    });

...

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    if (resultCode != Activity.RESULT_OK)
    {
        return;
    }
    ...
    else if (requestCode == REQUEST_IMAGE)
    {
        String pathToInternallyStoredImage = CameraUtils.saveToInternalStorage(getActivity(), imageUri);
        mMyObject.setImagePath(pathToInternallyStoredImage);

        //verify imagePath exists, both return correct path
        Log.d("onActivityResult pathToInternallyStoredImage", pathToInternallyStoredImage);
        Log.d("onActivityResult mMyObject.getImagePath", mMyObject.getImagePath());

        isImageButtonFirstClick = false;
        preferences.edit().putBoolean("isImageButtonFirstClick", isImageButtonFirstClick).commit();
    }

DialogFragment:

public static InputImageFragment newInstance(String imagePath)
{
    Bundle args = new Bundle();
    args.putSerializable(EXTRA_IMAGEPATH, imagePath);

    InputImageFragment fragment = new InputImageFragment();
    fragment.setArguments(args);

    return fragment;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    String imagePath = (String) getArguments.getSerializable(EXTRA_IMAGEPATH);

    try
    {
        Log.d("onCreateDialog imagePath", imagePath);
        //returns null...
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

    View v = getActivity().getLayoutInflater().inflate(R.layout.dialog_input_image, null);

    final ImageView imageView = (ImageView) v.findViewById(R.id.dialogInputImageView);
    Bitmap image = BitmapFactory.decodeFile(imagePath);
    imageView.setImageBitmap(image);

    return new AlertDialog.Builder(getActivity())
            .setView(v)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int whichButton)
                {
                    dialog.cancel();
                }
            })
            .create();
}

}

This returns a NullPointerException, and from my reading on BitmapFactory, it's either because the file name is null or cannot be decoded into a bitmap.

10-13 17:10:39.498 5330-5330/myPackageName E/BitmapFactory﹕ Unable to decode stream: java.lang.NullPointerException

The dialog is shown, but it is just an empty box with anOK button.

I've read of similar problems, where the issue was that the ImageView itself was null. I don't think this is the problem here, but below is the XML dialog_input_image. I've tried tinkering around with the XML, and I've had the ImageView as the child of a FrameLayout similar to other examples I've seen, but I get the same error.

<?xml version="1.0" encoding="utf-8"?>

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialogInputImageView"
    android:orientation="vertical"
    android:scaleType="centerInside"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
</ImageView>

I'm new to Android so I'm not sure where I'm going wrong. Any help appreciated, thanks!

Community
  • 1
  • 1
pez
  • 3,859
  • 12
  • 40
  • 72
  • where u `inflating` the layout in `onCreateView` – Kaushik Oct 15 '14 at 04:49
  • @kaushik Since this is a `DialogFragment` I don't call `onCreateView`. I inflate the layout in `onCreateDialog` then call `setView(v)` when I am returning a new `AlertDialog.Builder` – pez Oct 15 '14 at 04:59
  • Is the Bitmap returned by BitmapFactory.decodeFile null? Attaching the logcat for this exception would definitely help. – Michael Krause Oct 15 '14 at 05:16
  • As far as I can see, the problem is potentially here: `String imagePath = (String) getArguments().getSerializable(EXTRA_IMAGEPATH);`: 1) Where and how are you passing the image path to the fragment? 2) If that is a simple path (String), why are you using `Serializable`? – ozbek Oct 15 '14 at 05:19
  • @MichaelKrause The logcat shows only that single line when I it calls `decodeFile`. @shoerat Please see the main post, I've added more code. – pez Oct 15 '14 at 05:35
  • @pez, please change `args.putSerializable(EXTRA_IMAGEPATH, imagePath);` to `args.putString(EXTRA_IMAGEPATH, imagePath);`. Also, change `String imagePath = getArguments().getString(EXTRA_IMAGEPATH);` to `String imagePath = getArguments().getString(EXTRA_IMAGEPATH, "abraka-dabra");` and log `imagePath` in next line. See if you are getting the correct path. – ozbek Oct 15 '14 at 05:39
  • @shoerat I just remembered why I used `get/putSerializable` instead of `get/putString`. `getString` requires API level 12 and my current min API level is 8. Is there a work-around? – pez Oct 15 '14 at 05:45
  • @pez : no its not it is supported from api lvl 1 [official documentation](http://developer.android.com/reference/android/os/Bundle.html#putString) – Kaushik Oct 15 '14 at 05:49
  • @kaushik I can call `getString(String key)` without an error, but calling `getString(String key, String defaultKey)` gives me the API error in Android Studio. – pez Oct 15 '14 at 05:54
  • @pez, probably you should pass the path here: `dialog.show(fm, DIALOG_IMAGE);`. You seem to be not using the `DIALOG_IMAGE` tag anyway anywhere. You may consider passing the path as a tag and retrieve it using `getTag()` method. – ozbek Oct 15 '14 at 05:55
  • + you don't really have to use `getString(String key, String defaultKey)`, it was just a suggestion and only needed to see if you are really getting the correct path. – ozbek Oct 15 '14 at 05:56
  • @shoerat I don't think the path is being saved correctly, even though I use `setImagePath` and verify its existence in `onActivityResult`. I'm not sure why it returns null later when I try to retrieve it. – pez Oct 15 '14 at 06:04

3 Answers3

1

The problem had nothing to do with BitmapFactory.decodeFile().

The problem was that when the user goes to take the picture, onPause is called. It checks if there is an existing image path, and if so, saves it to SharedPreferences. The first time the user opens the app, no image path will exist so nothing is saved. After the picture is taken, onResume is called and attempts to retreive an image path from SharedPreferences, but ended up assigning the default value of null since no image path existed. I had been using a boolean to keep track of when to retreive the information in onResume, but a much better solution was simply to check if the value was null before attempting to retrieve it.

    if (preferences.getString("imagePath", null) != null)
    {
        myObject.setImagePath(preferences.getString("imagePath", null));
    }

The original code would have worked, assuming an image path already existed. But it wouldn't have worked the first time.

I apologize for the confusion, and thank you to everyone who tried to help. Although the problem was something unrelated to your answers (and that was my fault), your answers were still helpful and I will implement them as I continue to learn.

pez
  • 3,859
  • 12
  • 40
  • 72
0

You'd better use the Context method getFilesDir() to read from your internal storage, like :

String image path = getFilesDir() .getAbsolutePath(); + "/myInternalPicturesDir/IMG_20141011_152840.jpg";
final ImageView imageView = (ImageView) v.findViewById(R.id.dialogInputImageView);
Bitmap image = BitmapFactory.decodeFile(imagePath);
imageView.setImageBitmap(image);
ToYonos
  • 16,469
  • 2
  • 54
  • 70
  • Thanks for the reply. Calling `getActivity().getFilesDir().getAbsolutePath();` from my `DialogFragment` simply returns `/data/data/myPackageName/files`. Wouldn't the resulting `imagePath` `String` still be the same? – pez Oct 11 '14 at 23:38
  • Could you past the full stack trace in your post ? – ToYonos Oct 11 '14 at 23:49
  • Sure. This is all it shows: `10-11 16:35:56.098 31000-31000/myPackageName E/BitmapFactory﹕ Unable to decode stream: java.lang.NullPointerException` – pez Oct 11 '14 at 23:51
  • Nope, it's just the one line every time I get the error. The only other things that show up around it are my own `Log.d` messages. – pez Oct 11 '14 at 23:55
  • myInternalPicturesDir has been created by your app ? – ToYonos Oct 11 '14 at 23:59
  • Yes, you can see the code for the `CameraUtils` class and how it is called [here](http://stackoverflow.com/a/26225233/3558874) if you think it would help. – pez Oct 12 '14 at 00:02
  • What does `new File(imagePath).exists();` give ? – ToYonos Oct 12 '14 at 08:13
  • Calling that in `onActivityResult` returns `true` – pez Oct 12 '14 at 15:51
  • Maybe your file is too big or something. If you set up a try catch between decodeFile and print the stack trace, maybe some usefull information will come – ToYonos Oct 12 '14 at 15:58
  • I've tried putting the `decodeFile` and `setImage` parts in a try/catch, but the stacktrace is still the same one line. Strange – pez Oct 12 '14 at 16:08
  • Try this : BitmapFactory.options options = new BitmapFactory.Options(); options.inSampleSize = 2; Bitmap image = BitmapFactory.decodeFile(imagePath, options); – ToYonos Oct 12 '14 at 16:59
  • Thanks for the suggestion. I don't think the problem is the filesize, but that didn't work either. The stacktrace is still the same also. – pez Oct 12 '14 at 17:38
0

Before changing your Uri to bitmap first get its path from code below and then set it

..........
Bitmap image = BitmapFactory.decodeFile(getRealPathFromURI(URI));
}

public String getRealPathFromURI(Uri contentURI) throws Exception {
    String result;
    Cursor cursor = context.getContentResolver().query(contentURI, null,
            null, null, null);
    if (cursor == null) { 
        result = contentURI.getPath();
    } else {
        cursor.moveToFirst();
        int idx = cursor
                .getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        result = cursor.getString(idx);
        cursor.close();
    }
    return result;
}
Avinash Kumar Pankaj
  • 1,700
  • 2
  • 18
  • 27