web-dev-qa-db-ja.com

Androidカメラインテント後にクラッシュする

私はアプリを公開していますが、基本的な機能の1つは、ユーザーが写真を撮って、その写真を外部ストレージの特定のフォルダーに保存できるようにすることです。

すべてが正常に動作しているようですが、写真を撮り、[完了]をクリックしてカメラを終了(そしてアクティビティに戻る)すると、アプリが強制的に閉じられ、ユーザーが表示されるという報告が2件ありますホーム画面に戻ります。

これは、Samsung Nexus SとGalaxy Tabで発生します。以下に、インテントを設定したことと、onActivityResult()で写真を保存および表示する方法を示すコードを掲載しました。カメラアプリを終了するために[完了]をクリックした後、クラッシュの原因となる可能性があることについてのガイダンスをいただければ幸いです。

繰り返しますが、これはほとんどのデバイスで正常に機能しているようですが、それらが私が取るべきもっと効率的で普遍的なアプローチであるかどうか疑問に思っていました。ありがとうございました

カメラインテントを起動する方法

   case ACTION_BAR_CAMERA:

        // numbered image name
        fileName = "image_" + String.valueOf(numImages) + ".jpg";


        output = new File(direct + File.separator + fileName); // create
                                                                    // output
        while (output.exists()) { // while the file exists
            numImages++; // increment number of images
            fileName = "image_" + String.valueOf(numImages) + ".jpg";
            output = new File(outputFolder, fileName);


        }
        camera = new   Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        uriSavedImage = Uri.fromFile(output); // get Uri of the output
        camera.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage); //pass in Uri to camera intent
        startActivityForResult(camera, 1);


        break;
    default:
        return super.onHandleActionBarItemClick(item, position);
    }
    return true;
}

OnActivityResult()の設定方法

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) { // If data was passed successfully

        Bundle extras = data.getExtras();

        //Bundle extras = data.getBundleExtra(MediaStore.EXTRA_OUTPUT);

        /*ad = new AlertDialog.Builder(this).create();
        ad.setIcon(Android.R.drawable.ic_menu_camera);
        ad.setTitle("Save Image");
        ad.setMessage("Save This Image To Album?");
        ad.setButton("Ok", this);

        ad.show();*/



        bmp = (Bitmap) extras.get("data"); // Set the bitmap to the bundle
                                            // of data that was just
                                            // received
        image.setImageBitmap(bmp); // Set imageview to image that was
                                    // captured
        image.setScaleType(ScaleType.FIT_XY);


    }

}
22
Jade Byfield

最初にそれを明確にしましょう-カメラからonActivityResultで画像データを取得する2つのオプションがあります。

1。保存する画像の正確な場所Uriを渡してカメラを開始します。

2。カメラを起動するだけでLoaction Uriを渡さない


1。最初のケースでは:

保存したい場所に画像Uriを渡してカメラを起動します。

String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/picture.jpg";  
File imageFile = new File(imageFilePath); 
Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri

Intent it = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
it.putExtra(Android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); 
startActivityForResult(it, CAMERA_RESULT);

OnActivityResultで次のように画像を受け取ります。

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

    if (RESULT_OK == resultCode) { 
        iv = (ImageView) findViewById(R.id.ReturnedImageView); 

        // Decode it for real 
        BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inJustDecodeBounds = false; 

        //imageFilePath image path which you pass with intent 
        Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 

        // Display it 
        iv.setImageBitmap(bmp); 
    }    
} 

2。2番目のケース:

Intent(data)で画像を受け取りたい場合は、画像Uriを渡さずにカメラを起動します。

Intent it = new Intent(Android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(it, CAMERA_RESULT); 

OnActivityResultでは、画像を次のように受け取ります。

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

    if (RESULT_OK == resultCode) { 
        // Get Extra from the intent 
        Bundle extras = data.getExtras(); 
        // Get the returned image from extra 
        Bitmap bmp = (Bitmap) extras.get("data"); 

        iv = (ImageView) findViewById(R.id.ReturnedImageView); 
        iv.setImageBitmap(bmp); 
    } 
} 

37

カメラボタンのクリックイベントで、これを試すことができます。

final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT,
                Uri.fromFile(getTempFile(this)));
        startActivityForResult(intent, TAKE_PHOTO_CODE);

        declare TAKE_PHOTO_CODE globally as:
        private static final int TAKE_PHOTO_CODE = 1;

コードにgetTempFile関数を追加します。これは、アプリのパッケージ名として指定されたフォルダーの下のsdcardでクリックしたmyImage.pngという名前の画像を保存するのに役立ちます。

private File getTempFile(Context context) {
        final File path = new File(Environment.getExternalStorageDirectory(),
                context.getPackageName());
        if (!path.exists()) {
            path.mkdir();
        }
        return new File(path, "myImage.png");
    }

OnActivityResult関数にこれを追加します。

if (requestCode == TAKE_PHOTO_CODE) {
                final File file = getTempFile(this);
                try {
                    Uri uri = Uri.fromFile(file);
                    Bitmap captureBmp = Media.getBitmap(getContentResolver(),
                            uri);
                    image.setImageBitmap(captureBmp);
                    } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

メモリの問題が発生した場合は、以下のコードを追加してください:

@Override
    protected void onPause() {
        image.setImageURI(null);
        super.onPause();
    }

これがお役に立てば幸いです

4
AkashG

3つの考えられる問題があなたの問題を引き起こしたと思われます:

  1. 一部のデバイスは、nullメソッドでextras.get("data");を呼び出すとonActivityResultを返すため、問題はNullPointerExceptionになる可能性があります。これを解決するには、正確なURIの場所を渡して、カメラアプリに保存場所を伝え、onActivityResultで使用して画像をBitmapとして取得する必要があります。 。

  2. 他の一部のデバイスは、Bitmap内のextras.get("data");のときにフルサイズonActivityResultを返します。ビットマップが大きすぎてOutOfMemmoryErrorが発生する可能性がある場合は、画像を小さいサイズでデコードして、メモリヒープをあまり消費しないようにする必要があります。この2つのリンクは、この状況で役立ちます。

    http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html

    BitmapFactory OOMが私を運転している

  3. 多分あなたの活動はGCによって破壊されるので、onSavedInstanceStateonRestoreInstanceStateを使用してActivityのデータを保存する必要があります。詳細は この以前の投稿 の回答を参照してください。

あなたがすでにこれらの問題に対処したかどうかはわかりません。

それが役に立てば幸い:)

3
Angelo

まず、リクエストコードを確認してください。他の誰かの結果をそこにキャッチしている可能性があります。次に、インテントのデータビットマップを使用しないでください-どちらかといえば小さいですが、キャプチャした画像を保存するパスを提供するため、そこに存在することはできません( ここ を参照)。したがって、yourリクエストのRESULT_OKを受け取ったときに、出力ファイルパスとして提供したURLを保存し、そこからビットマップを読み取ります。

    ...
    // save your file uri, not necessarily static
    mUriSavedImage = Uri.fromFile(output);
    startActivityForResult(camera, MY_REQUEST_CODE);
    /* Make a String like "com.myname.MY_REQUEST_CODE" and hash it into int to give it
    a bit of uniqueness */
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == MY_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
             Bitmap bmp = BitmapFactory.decodeFile(mUriSavedImage);
             if (bmp != null) {
                 image.setImageBitmap(bmp); // Set imageview to image that was
                                // captured
                 image.setScaleType(ScaleType.FIT_XY);
             } else {
                 Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
             }
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
1
Ivan Bartsov

こんにちは私は答えが出たことを知っていますが、これも私が見つけた最も簡単な解決策の一つなので

これは、デバイス自体を悩ませている例です。

AndroidCameraUtils -プロジェクトをダウンロードし、ライブラリプロジェクトから以下に含めることで、使用できるコードスニペットです!

private void setupCameraIntentHelper() {
mCameraIntentHelper = new CameraIntentHelper(this, new CameraIntentHelperCallback() {
    @Override
    public void onPhotoUriFound(Date dateCameraIntentStarted, Uri photoUri, int rotateXDegrees) {
        messageView.setText(getString(R.string.activity_camera_intent_photo_uri_found) + photoUri.toString());

        Bitmap photo = BitmapHelper.readBitmap(CameraIntentActivity.this, photoUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 300, rotateXDegrees);
            ImageView imageView = (ImageView) findViewById(de.ecotastic.Android.camerautil.sample.R.id.activity_camera_intent_image_view);
            imageView.setImageBitmap(photo);
        }
    }

    @Override
    public void deletePhotoWithUri(Uri photoUri) {
        BitmapHelper.deleteImageWithUriIfExists(photoUri, CameraIntentActivity.this);
    }

    @Override
    public void onSdCardNotMounted() {
        Toast.makeText(getApplicationContext(), getString(R.string.error_sd_card_not_mounted), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onCanceled() {
        Toast.makeText(getApplicationContext(), getString(R.string.warning_camera_intent_canceled), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onCouldNotTakePhoto() {
        Toast.makeText(getApplicationContext(), getString(R.string.error_could_not_take_photo), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onPhotoUriNotFound() {
        messageView.setText(getString(R.string.activity_camera_intent_photo_uri_not_found));
    }

    @Override
    public void logException(Exception e) {
        Toast.makeText(getApplicationContext(), getString(R.string.error_sth_went_wrong), Toast.LENGTH_LONG).show();
        Log.d(getClass().getName(), e.getMessage());
    }
});
}

@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    mCameraIntentHelper.onSaveInstanceState(savedInstanceState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    mCameraIntentHelper.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    mCameraIntentHelper.onActivityResult(requestCode, resultCode, intent);
}
}

[〜#〜]ノート[〜#〜]:-私はカメラユーティリティの多くの例を試しましたが、もちろん、初心者のためにそれを処理する別の方法がありますコアコンセプトにあまり慣れていない人は、このプロジェクトの方が快適です。ありがとう!

0
Hardy

この link に記載されている手順に従ってください。これがあなたに役立つことを願っています。

OR

クラッシュせずに画像を取得する

MainActivityに以下のコードを記述します

// Storage for camera image URI components 
private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";      
private final static String CAPTURED_PHOTO_URI_KEY = "mCapturedImageURI"; 

// Required for camera operations in order to save the image file on resume.    
private String mCurrentPhotoPath = null; 
private Uri mCapturedImageURI = null; 

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) { 
   if (mCurrentPhotoPath != null) {            
     savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath); 
   } 
  if (mCapturedImageURI != null) {  
     savedInstanceState.putString(CAPTURED_PHOTO_URI_KEY, mCapturedImageURI.toString()); 
  } 
  super.onSaveInstanceState(savedInstanceState); 
} 

@Override 
protected void onRestoreInstanceState(Bundle savedInstanceState) {

   if (savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
       mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY); 
   } 
   if (savedInstanceState.containsKey(CAPTURED_PHOTO_URI_KEY)) {
   mCapturedImageURI = Uri.parse(savedInstanceState.getString(CAPTURED_PHOTO_URI_KEY)); 
   } 
   super.onRestoreInstanceState(savedInstanceState); 
}
0
Kailas

私は同じ問題に直面しました。どうやら修正は、uriSavedImageを静的にすることです。これが最善の方法かどうかはわかりません。しかし、これは私にとってはうまくいきます。

0
san

Samsungデバイスの場合、AndroidManifest.xmlファイルの1行の下に追加します

Android:configChanges = "orientation | screenSize"

これがうまくいくことを願っています

0