0

我一直在努力创建一个允许用户拍照并使用意图通过电子邮件发送此图像的活动。我创建了文件名并将其存储在一个字符串中,但它最终将它的值拿走了。当它被重置为 null 时,我最终创建了另一个字符串变量来保存它的值,这样我就可以确保没有任何东西可以更改它的值,但第二个字符串也最终为 null。我使用字符串的值并将其传递给意图,以便将刚刚拍摄的图像添加为附件。谁能看到这个变量为什么以及如何改变它的值?

这是我的课,有评论:

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;
    }
}

如果有人能阐明这是如何发生的,我将不胜感激。

这是 logcat,我打开活动,拍照,保存,然后返回活动视图,我按下分享,吐司显示 temp 的值,同时选择器打开。

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
4

4 回答 4

4

您应该将字符串永久保存SharedPreferences、数据库或通用文件中。

当您离开 Activity 以使用内置相机应用拍照时,您的应用会进入后台。如果需要额外的内存,后台的任何应用程序都有被操作系统杀死的风险。如果发生这种情况,您的所有变量都将重置为其默认的空值...



从您的 LogCat 中添加:

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

我猜第 94 行是:

mImageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);

如果应用程序在幕后被销毁并重新启动,这是有道理的。当应用程序像这样完全重新启动时, onCreate()调用,而不是createImageFile()任何其他方法。

也保存mCurrentPhotoPath在 SharedPreferences 中,并在为 null时imageFileName恢复这些值。onActivityResult()mCurrentPhotoPath


使用 SharedPreferences
将这些方法添加到您的 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", "");
}

我忽略temp了,正如您所说,这只是imageFileName您调试时的重复。
现在我们需要在适当的时候调用这些方法。首先让我们在离开 Activity 拍照之前保存两个字符串:

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

然后检查是否需要重新加载这些值onActivityResult()

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

    mImageBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath);
    ...
于 2012-11-25T17:28:04.570 回答
0

尝试初始化您的变量:

String temp = "";
于 2012-11-25T17:22:30.337 回答
0

是的,初始化您的变量防止获得 NullPointerException,但问题是,为什么此时它为空。你确定,如果你得到一个空字符串,就会拍一张照片吗?请显示堆栈跟踪,您的 CreateImageFile-Method 可能有问题,此方法是否会引发异常?如果是,则无法初始化此字符串。

于 2012-11-25T17:29:17.697 回答
0

我建议不要将其保存在 shareprefrences 中,而是将其保存在 savedInstanceState 中。

您可以致电存储:

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

并在 onCreate 调用中恢复:

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

所以这就是发生的事情:

  1. mCurrentPhotoPath 是事先创建的文件的路径
  2. 用户转到相机并在 Activity 被销毁之前保存 mCurrentPhotoPath。
  3. 用户返回 Activity 并在 onActivityResult 之前调用 onCreate。4.在onCreate里面,Activity恢复mCurrentPhotoPath
  4. onActivityResult 被调用

您还可以查看这些页面以获得更好的解释:

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

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

于 2016-11-24T18:59:57.107 回答