deucalion0
deucalion0

Reputation: 2440

String variable ends up null, and I do not know why

I have been trying hard to create an activity which allows a user to take a photo and email this image using intents. I create the file name and store it in a string, but it eventually gets it value taken away. When it was being reset to null I ended up creating another string variable to hold its value so I could ensure nothing had access to changing its value, but the second string also ends up as null. I use the value of the string and pass it to the intent in order to add the just taken image as an attachment. Can anyone see why and how this variable is having its value changed?

Here is my class, with comments:

public class ImproveActivity extends Activity implements OnClickListener{
private static final String JPEG_FILE_PREFIX = "Improve_";
private static final String JPEG_FILE_SUFFIX = ".jpg";
private Bitmap mImageBitmap;
private ImageView mImageView;
private File storageDir;
private String mCurrentPhotoPath;
Button share, capture;
private String _path;
private File f;
//This variable holds file name
private String imageFileName;
//I am storing the file name variable here to keep its value
private String temp;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
       setContentView(R.layout.improve_layout);
       mImageView = (ImageView)findViewById(R.id.imgview);
       capture = (Button)findViewById(R.id.capture);
       share = (Button)findViewById(R.id.share);

       capture.setOnClickListener(this);
       share.setOnClickListener(this);

}

private void dispatchTakePictureIntent() {

    if(isIntentAvailable(getApplicationContext(), MediaStore.ACTION_IMAGE_CAPTURE)){

        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        ;
        try {
            //f is the image
            f = createImageFile();

            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
            startActivityForResult(takePictureIntent, 1);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "error creating image", Toast.LENGTH_LONG).show();
        }

    }
    else{
        Toast.makeText(getApplicationContext(), "no camera available", Toast.LENGTH_LONG).show();
    }


}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent){
    Toast.makeText(getApplicationContext(), "returning", Toast.LENGTH_LONG).show();

    if (requestCode == 1) {

        mImageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);
        if (mImageBitmap == null) {
            // bitmap still null
        } else {
            // set bitmap in imageview
            mImageView.setImageBitmap(mImageBitmap);
        }
    }

}

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = 
        new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
   imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
   //display the current image file name
    Toast.makeText(getApplicationContext(), imageFileName, Toast.LENGTH_LONG).show();

    File file = new File(getAlbumDir().getAbsolutePath());
    file.mkdirs();              
    Toast.makeText(getApplicationContext(), imageFileName, Toast.LENGTH_LONG).show();
    File image = File.createTempFile(
        imageFileName, 
        JPEG_FILE_SUFFIX  
    );


    mCurrentPhotoPath = image.getAbsolutePath();
    temp = imageFileName;
    return image;

}

private File getAlbumDir() {
    return storageDir = new File(
            Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DCIM
            ), 
            "Camera"
        );
}

public static boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list =
            packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}


@Override
public void onClick(View v) {
    switch(v.getId()){
    case R.id.capture :
        dispatchTakePictureIntent();
        //displaying the value of the string imageFileName, it is what it should be, the file name
        Toast.makeText(getApplicationContext(), imageFileName, Toast.LENGTH_LONG).show();

        //displaying the file name in temp at this point it is still the file name I need
        Toast.makeText(getApplicationContext(), "temp is " +temp, Toast.LENGTH_LONG).show();
        break;
        //Once the image is saved, clicking share to open chooser
    case R.id.share:

        //displaying the temp string the file name is gone it is now null ????
        Toast.makeText(getApplicationContext(), "temp is " +temp, Toast.LENGTH_LONG).show();

        Intent picMessageIntent = new Intent(android.content.Intent.ACTION_SEND);  
        picMessageIntent.setType("image/jpg");  
        File downloadedPic =  new File(  
            Environment.getExternalStoragePublicDirectory(  
            Environment.DIRECTORY_DCIM),  
            "Camera/"+ temp+"jpg");  //I want to use the file name string to send the image via email
        picMessageIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(downloadedPic));  
        startActivity(Intent.createChooser(picMessageIntent, "Send your picture using:"));  
        break;
    }
}

If anyone could shed some light on how this is happening I would be grateful.

Here is the logcat, I open the activity, take a photo, save it, then it goes back to the activity view, I press share and the toast displays the value of temp while the chooser opens.

11-25 17:56:34.573: D/dalvikvm(12037): GC_EXTERNAL_ALLOC freed 1176 objects / 87312 bytes in 53ms
11-25 17:56:39.313: W/IInputConnectionWrapper(12037): showStatusIcon on inactive InputConnection
11-25 17:56:49.803: W/System.err(12037): java.lang.NullPointerException: Argument must not be null
11-25 17:56:49.808: W/System.err(12037):    at java.io.FileInputStream.<init>(FileInputStream.java:78)
11-25 17:56:49.808: W/System.err(12037):    at java.io.FileInputStream.<init>(FileInputStream.java:134)
11-25 17:56:49.808: W/System.err(12037):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:349)
11-25 17:56:49.808: W/System.err(12037):    at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:399)
11-25 17:56:49.808: W/System.err(12037):    at com.seweb.app.ImproveActivity.onActivityResult(ImproveActivity.java:94)
11-25 17:56:49.808: W/System.err(12037):    at android.app.Activity.dispatchActivityResult(Activity.java:3890)
11-25 17:56:49.808: W/System.err(12037):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3511)
11-25 17:56:49.808: W/System.err(12037):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3115)
11-25 17:56:49.808: W/System.err(12037):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3143)
11-25 17:56:49.813: W/System.err(12037):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2684)
11-25 17:56:49.813: W/System.err(12037):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
11-25 17:56:49.813: W/System.err(12037):    at android.app.ActivityThread.access$2400(ActivityThread.java:125)
11-25 17:56:49.813: W/System.err(12037):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
11-25 17:56:49.818: W/System.err(12037):    at android.os.Handler.dispatchMessage(Handler.java:99)
11-25 17:56:49.818: W/System.err(12037):    at android.os.Looper.loop(Looper.java:123)
11-25 17:56:49.818: W/System.err(12037):    at android.app.ActivityThread.main(ActivityThread.java:4627)
11-25 17:56:49.818: W/System.err(12037):    at java.lang.reflect.Method.invokeNative(Native Method)
11-25 17:56:49.818: W/System.err(12037):    at java.lang.reflect.Method.invoke(Method.java:521)
11-25 17:56:49.823: W/System.err(12037):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
11-25 17:56:49.823: W/System.err(12037):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
11-25 17:56:49.823: W/System.err(12037):    at dalvik.system.NativeStart.main(Native Method)
11-25 17:56:50.273: D/dalvikvm(12037): GC_EXTERNAL_ALLOC freed 1920 objects / 108152 bytes in 136ms

Upvotes: 0

Views: 1166

Answers (4)

Omid Aminiva
Omid Aminiva

Reputation: 667

I suggest instead of saving it in shareprefrences save it in savedInstanceState.

you can call to store:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putAll(getIntent().getExtras());
    savedInstanceState.putString("currentPhotoPath", mCurrentPhotoPath);
    super.onSaveInstanceState(savedInstanceState);
}

and in onCreate call to restore:

        if (savedInstanceState != null) {
mCurrentPhotoPath = savedInstanceState.getString("currentPhotoPath", mCurrentPhotoPath);
    }

So this is what happens:

  1. mCurrentPhotoPath is path to file that is created before hand
  2. User goes to Camera and before Activity is destroyed mCurrentPhotoPath is saved.
  3. User returns to Activity and onCreate is called before onActivityResult. 4. Inside onCreate, Activity restores mCurrentPhotoPath
  4. onActivityResult is called

You can also check these pages to get better explenation:

https://developer.android.com/training/basics/activity-lifecycle/recreating.html

https://developer.android.com/training/camera/photobasics.html

Upvotes: 0

Sam
Sam

Reputation: 86948

You should permanently save your Strings in a SharedPreferences, a database, or a generic file.

When you leave your Activity to take a photo with the built-in camera app, your app goes into the background. Any app in the background runs the risk of being killed by the OS if extra memory is needed. If this happens all of your variables are reset to their default null values...


Addition
From your LogCat:

java.lang.NullPointerException: Argument must not be null
    ...
    at com.seweb.app.ImproveActivity.onActivityResult(ImproveActivity.java:94)

I'm guessing that line 94 is:

mImageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);

which makes sense if the app is destroyed and restarted behind the scenes. When the app is completely restarted like this, only onCreate() is called, not createImageFile() or any other methods.

Save mCurrentPhotoPath in the SharedPreferences as well imageFileName and restore these values in onActivityResult() whenever mCurrentPhotoPath is null.


Using SharedPreferences
Add these methods to your Activity:

private void savePreferences(){
    // We need an Editor object to make preference changes.
    SharedPreferences.Editor editor = getPreferences(MODE_PRIVATE).edit();
    editor.putString("imageFileName", imageFileName);
    editor.putString("mCurrentPhotoPath", mCurrentPhotoPath);

    // Commit the edits!
    editor.commit();
}

private void restorePreferences() {
    SharedPreferences settings = getPreferences(MODE_PRIVATE);
    imageFileName = settings.getString("imageFileName", "");
    mCurrentPhotoPath = settings.getString("mCurrentPhotoPath", "");
}

I ignored temp, as you said it was just a duplicate of imageFileName while you were debugging.
Now we need to call these methods at appropriate times. First lets save both Strings just before leaving the Activity to take a picture:

try {
    savePreferences();
    ...
    startActivityForResult(takePictureIntent, 1);
} 

Then check if you need to reload these values in onActivityResult():

if (requestCode == 1) {
    if(mCurrentPhotoPath == null)
        restorePreferences();

    mImageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);
    ...

Upvotes: 4

Opiatefuchs
Opiatefuchs

Reputation: 9870

Yes initialize your variable prevent to get a NullPointerException, but the question is, why is it null at this point. Are you sure, that a photo is taken if you get a null-string? Please show stacktrace, maybe something is going wrong with Your CreateImageFile-Method, does this method sometomes throws an Exception? If yes, then this String couldn´t be initialized.

Upvotes: 0

Artyom Kiriliyk
Artyom Kiriliyk

Reputation: 2513

Try to initialize your variable:

String temp = "";

Upvotes: 0

Related Questions