65

私はこれが多くの異なる方法で尋ねられたことを知っていますが、それでもデフォルトのフォルダからギャラリー画像を削除できないようです。ファイルをSDカードに正しく保存しており、そのファイルを正常に削除できますが、Cameraフォルダーの下に表示されるデフォルトのギャラリー画像ファイルは削除されません。

ファイルはすでにSDカードに保存されているので、アクティビティが返されたら画像を削除したいのですが/Coupon2

助言がありますか?

public void startCamera() {
    Log.d("ANDRO_CAMERA", "Starting camera on the phone...");

    mManufacturerText = (EditText) findViewById(R.id.manufacturer);
    String ManufacturerText = mManufacturerText.getText().toString();
    String currentDateTimeString = new Date().toString();

    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File filedir = new File(Environment.getExternalStorageDirectory()+"/Coupon2");
    filedir.mkdirs();

    File file = new File(Environment.getExternalStorageDirectory()+"/Coupon2", ManufacturerText+"-test.png");
    outputFileUri = Uri.fromFile(file);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);

    startActivityForResult(intent, CAMERA_PIC_REQUEST);
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == CAMERA_PIC_REQUEST && resultCode == -1) {  
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.putExtra("crop", "true");
        intent.putExtra("scale", "true");

        intent.putExtra("return-data", false);
        intent.setDataAndType(outputFileUri, "image/*");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
        startActivityForResult(intent, CAMERA_CROP_REQUEST);
    }else { 
        SetImage();
        saveState();
    }
}
4

13 に答える 13

70

私のアプリケーションでは、写真を撮るためにインテントを呼び出す必要があります。写真をギャラリーに入れることはできませんが、SDカードの特定のディレクトリに置く必要があります。

もともと私はEXTRA_OUTPUTを使用していましたが、すぐに次のことを発見しました。-一部のデバイスはそれを完全に使用し、ギャラリーをスキップします。-一部のデバイスはそれを完全に無視し、ギャラリーのみを使用します。-一部のデバイスは、フルサイズの画像を実際に吸い込んでギャラリーに保存し、サムネイルを目的の場所にのみ保存します。(HTCあなたはあなたが誰であるかを知っています...)

ですから、終わったらギャラリーファイルをやみくもに削除することはできません。最後に追加した写真は、削除したい写真である場合とそうでない場合があります。また、後で自分のファイルを置き換えてそのファイルをコピーする必要があるかもしれません。私の活動は2000行であり、私の会社はすべてのコードを投稿したくないので、これを行うために必要なメソッドのみを投稿しています。うまくいけば、これがお役に立てば幸いです。

また、これは私の最初のAndroidアプリケーションです。私が知らないより良い方法があったとしても驚かないでしょうが、これが私のために働いていることです!

だから、ここに私の解決策があります:

まず、私のアプリケーションコンテキストでは、変数を次のように定義します。

public ArrayList<String> GalleryList = new ArrayList<String>();

次に、私のアクティビティでは、ギャラリー内のすべての写真のリストを取得するメソッドを定義します。

private void FillPhotoList()
{
   // initialize the list!
   app.GalleryList.clear();
   String[] projection = { MediaStore.Images.ImageColumns.DISPLAY_NAME };
   // intialize the Uri and the Cursor, and the current expected size.
   Cursor c = null; 
   Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
   //
   // Query the Uri to get the data path.  Only if the Uri is valid.
   if (u != null)
   {
      c = managedQuery(u, projection, null, null, null);
   }

   // If we found the cursor and found a record in it (we also have the id).
   if ((c != null) && (c.moveToFirst())) 
   {
      do 
      {
        // Loop each and add to the list.
        app.GalleryList.add(c.getString(0));
      }     
      while (c.moveToNext());
   }
}

新しい画像の一意のファイル名を返すメソッドは次のとおりです。

private String getTempFileString()
{
   // Only one time will we grab this location.
   final File path = new File(Environment.getExternalStorageDirectory(), 
         getString(getApplicationInfo().labelRes));
   //
   // If this does not exist, we can create it here.
   if (!path.exists())
   {
      path.mkdir();
   }
   //
   return new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg").getPath();
}

アクティビティには、現在のファイルに関する情報を格納する3つの変数があります。文字列(パス)、ファイル変数、およびそのファイルへのURI:

public static String sFilePath = ""; 
public static File CurrentFile = null;
public static Uri CurrentUri = null;

これらを直接設定することはありません。ファイルパスでセッターを呼び出すだけです。

public void setsFilePath(String value)
{
   // We just updated this value. Set the property first.
   sFilePath = value;
   //
   // initialize these two
   CurrentFile = null;
   CurrentUri = null;
   //
   // If we have something real, setup the file and the Uri.
   if (!sFilePath.equalsIgnoreCase(""))
   {
      CurrentFile = new File(sFilePath);
      CurrentUri = Uri.fromFile(CurrentFile);
   }
}

今、私は写真を撮るインテントを呼び出します。

public void startCamera()
{
   Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
   // Specify the output. This will be unique.
   setsFilePath(getTempFileString());
   //
   intent.putExtra(MediaStore.EXTRA_OUTPUT, CurrentUri);
   //
   // Keep a list for afterwards
   FillPhotoList();
   //
   // finally start the intent and wait for a result.
   startActivityForResult(intent, IMAGE_CAPTURE);
}

これが完了し、アクティビティが戻ってきたら、次のコードを使用します。

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
   if (requestCode == IMAGE_CAPTURE)
   {
      // based on the result we either set the preview or show a quick toast splash.
      if (resultCode == RESULT_OK)
      {
         // This is ##### ridiculous.  Some versions of Android save
         // to the MediaStore as well.  Not sure why!  We don't know what
         // name Android will give either, so we get to search for this
         // manually and remove it.  
         String[] projection = { MediaStore.Images.ImageColumns.SIZE,
                                 MediaStore.Images.ImageColumns.DISPLAY_NAME,
                                 MediaStore.Images.ImageColumns.DATA,
                                 BaseColumns._ID,};
         //    
         // intialize the Uri and the Cursor, and the current expected size.
         Cursor c = null; 
         Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
         //
         if (CurrentFile != null)
         {               
            // Query the Uri to get the data path.  Only if the Uri is valid,
            // and we had a valid size to be searching for.
            if ((u != null) && (CurrentFile.length() > 0))
            {
               c = managedQuery(u, projection, null, null, null);
            }
            //   
            // If we found the cursor and found a record in it (we also have the size).
            if ((c != null) && (c.moveToFirst())) 
            {
               do 
               {
                  // Check each area in the gallary we built before.
                  boolean bFound = false;
                  for (String sGallery : app.GalleryList)
                  {
                     if (sGallery.equalsIgnoreCase(c.getString(1)))
                     {
                        bFound = true;
                        break;
                     }
                  }
                  //       
                  // To here we looped the full gallery.
                  if (!bFound)
                  {
                     // This is the NEW image.  If the size is bigger, copy it.
                     // Then delete it!
                     File f = new File(c.getString(2));

                     // Ensure it's there, check size, and delete!
                     if ((f.exists()) && (CurrentFile.length() < c.getLong(0)) && (CurrentFile.delete()))
                     {
                        // Finally we can stop the copy.
                        try
                        {
                           CurrentFile.createNewFile();
                           FileChannel source = null;
                           FileChannel destination = null;
                           try 
                           {
                              source = new FileInputStream(f).getChannel();
                              destination = new FileOutputStream(CurrentFile).getChannel();
                              destination.transferFrom(source, 0, source.size());
                           }
                           finally 
                           {
                              if (source != null) 
                              {
                                 source.close();
                              }
                              if (destination != null) 
                              {
                                 destination.close();
                              }
                           }
                        }
                        catch (IOException e)
                        {
                           // Could not copy the file over.
                           app.CallToast(PhotosActivity.this, getString(R.string.ErrorOccured), 0);
                        }
                     }
                     //       
                     ContentResolver cr = getContentResolver();
                     cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
                        BaseColumns._ID + "=" + c.getString(3), null);
                     break;                        
                  }
               } 
               while (c.moveToNext());
            }
         }
      }
   }      
}
于 2011-07-06T16:56:36.243 に答える
18

これにより、ギャラリーからファイルが削除されます。

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

    if (requestCode == CAMERA_PIC_REQUEST && resultCode == RESULT_OK) { 

        /* Copy the file to other directory or whatever you want */

        // mContext is the context of the activity
        mContext.getContentResolver().delete(data.getData(), null, null);
    }
 }

EXTRA_OUTPUTについては標準的な動作ではありません。この疑似アルゴリズムはすべての場合に機能するはずだと思います。

1)EXTRA_OUTPUTを使用しないでください。画像/写真は常にギャラリーの場所に移動します。

2)ファイルをギャラリーの場所から目的の場所にコピーします。

3)ギャラリーからファイルを(上のコードで)削除します。

しかしもちろん、それは完璧すぎるようです...一部のデバイス(たとえば、Android2.3の元のGalaxyTab)では、ACTION_IMAGE_CAPTUREでEXTRA_OUTPUTを使用する必要があります。これがないと、インテントは機能しません。

于 2013-01-30T12:39:45.207 に答える
15

誰かがこの問題のより簡単な回避策を探しているなら、これが私が問題を解決した方法です。

キャプチャボタンがあり、それを押すとインテントが送信されます。追加したのは、画像メディアストアから最後のIDを取得して保存することです。

/**
 * Gets the last image id from the media store
 * @return
 */
private int getLastImageId(){
    final String[] imageColumns = { MediaStore.Images.Media._ID };
    final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
    final String imageWhere = null;
    final String[] imageArguments = null;
    Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy);
    if(imageCursor.moveToFirst()){
        int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
        imageCursor.close();
        return id;
    }else{
        return 0;
    }
}

次に、アクティビティが戻ったら、このコードを実行してキャプチャ前の最後の画像IDを確認し、キャプチャ後の画像のクエリで記録されたIDよりも大きいIDを取得し、それより大きい場合は、カメラに指定した場所にあるレコードを削除します保存します。

/*
 * Checking for duplicate images
 * This is necessary because some camera implementation not only save where you want them to save but also in their default location.
 */
final String[] imageColumns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.SIZE, MediaStore.Images.Media._ID };
final String imageOrderBy = MediaStore.Images.Media._ID+" DESC";
final String imageWhere = MediaStore.Images.Media._ID+">?";
final String[] imageArguments = { Integer.toString(MyActivity.this.captureLastId) };
Cursor imageCursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, imageWhere, imageArguments, imageOrderBy);
if(imageCursor.getCount()>1){
    while(imageCursor.moveToNext()){
        int id = imageCursor.getInt(imageCursor.getColumnIndex(MediaStore.Images.Media._ID));
        String path = imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA));
        Long takenTimeStamp = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN));
        Long size = imageCursor.getLong(imageCursor.getColumnIndex(MediaStore.Images.Media.SIZE));
        if(path.contentEquals(MyActivity.this.capturePath)){
            // Remove it
            ContentResolver cr = getContentResolver();
            cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media._ID + "=?", new String[]{ Long.toString(id) } );
            break;
        }
    }               
}
imageCursor.close();

私にとって、これははるかに簡単な解決策であり、この問題が発生していたHTCでテストしました。

別の注意点として、私は元々*_ID*ではなく*DATE_TAKEN*をパラメーターとして使用していましたが、エミュレーターでインテントを介してキャプチャされた画像の一部で、ミリ秒の* DATE_TAKEN *時間が1000倍されたため、バグが発生したようです。 *_ID*に切り替えました。これははるかに堅牢なようです。

于 2011-12-19T00:15:13.367 に答える
5

さて、私が思う全体の問題は、起こっていない別のアプリケーションから特定の結果を期待しているという事実から来ていると思います。これは(明確にするために)-

  • アプリケーションは画像をキャプチャしないため、写真を撮ることができるアクティビティを起動します。
  • picutreを保存したい場所を他のアプリケーションに伝えます
  • 保存した画像を指定した場所で使用します。
  • しかし、問題は、他のアプリケーションも別の場所に画像を保存していることです。これは望ましくありません。

次に、画像をキャプチャしている他のアプリケーションの観点から見てみましょう。2つのシナリオを考えてみましょう(どちらが可能ですか)-

  • まず、ファイル名または画像を保存する場所のオプションを指定してアプリケーションを起動します。
  • 次に、ファイル名や画像を保存する場所などの追加情報なしでアプリケーションが起動されます(これは、キャプチャアプリがメニューから直接起動された場合に発生する可能性があります)

理想的には、fileNameや場所などの追加情報がある場合はその場所を使用する必要があり、そうでない場合は自分の場所を使用できます。しかし、残念ながら、私たちは理想的な世界から来ました。カメラアプリケーションを起動したときに何が起こるかについては何も書かれていないため、カメラアプリの開発者は独自の解釈をします。

デバイスが異なれば、デフォルトとして設定されているカメラアプリケーションも異なるため(はい、通常はストックカメラが交換されます)、得られる結果は異なります。

そのため、一部のカメラでは、他の1つの場所にのみ保存される場合があり、Cameraフォルダーにも保存される場合があります(カメラアプリケーションは常にキャプチャされた画像をカメラフォルダーに保存し、別の場所に保存することはボーナスです。アプリケーション)

fileNameをカメラアプリケーションに渡すだけの場合、アプリケーションは1枚の写真を撮っただけで戻る必要がありますか?私はそうは思わない。では、そのようなシナリオでは何をすべきでしょうか?それはすべて非常に曖昧または灰色の領域です。

カメラフォルダに保存したくない場合は、最近キャプチャした画像のファイル名を取得して、アプリケーションから削除できるかどうかを確認してください。または、カメラアプリケーションに保存する必要がある場所を指定せずに、ファイル名を取得して目的の場所に移動します。

ファイル名がわからない場合は、他のアプリケーション開発者に翻弄されます。(ねえ!それも彼のせいではありません、彼はそれを彼が望むように設計しただけです!)

于 2011-06-27T10:03:14.060 に答える
2

やりたいことができないと思います。それは悲しいことですが、私は別の答えを見つけることができません。

あなたがグーグルカメラの実装で働いているなら、それはうまく働きます。EXTRA_OUTPUTが指定されているギャラリーに写真を保存しないだけです。

しかし、他のデバイスに直面すると、まったく異なることをする可能性があります。これは、HTC、LG、その他の一部にカスタムカメラの実装があり、それについては何もできないためです。そのままにしておくことも、必要な方法で正確に機能する独自のカメラを作成することもできます。

実際にはこの質問とは関係ありませんが、ある日、CROPインテントが一部のデバイスで機能しないことがわかります(http://groups.google.com/group/android-developers/browse_frm/thread/2dd647523926192c/4b6d087073a39607 ?tvc = 1&pli = 1)。したがって、必要な場合は、自分で作成する必要があります。

于 2011-06-27T14:54:27.577 に答える
2

これは解決するのが簡単な作業ではありませんが、トリッキーな方法に近づく可能性があります。誰かがこれのためのシンプルで実用的な解決策を必要とする場合。以下のコードを試してください。

  1. カメラインテントを呼び出す前に、現在の時間をミリ秒単位で保存します。
  2. OnActivityResultは、撮影日がステップ1のミリ秒よりも大きい画像URIを照会します。そして、ファイルを削除します。それでおしまい。
String[] projection = {MediaStore.Images.ImageColumns.SIZE,
                MediaStore.Images.ImageColumns.DISPLAY_NAME,
                MediaStore.Images.ImageColumns.DATA,
                BaseColumns._ID,MediaStore.Images.ImageColumns.DATE_ADDED};
        final String imageOrderBy = MediaStore.Images.Media._ID + " DESC";
        final String selection = MediaStore.Images.Media.DATE_TAKEN+" > "+mImageTakenTime;
        //// intialize the Uri and the Cursor, and the current expected size.
        Cursor c = null;
        Uri u = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        c = getActivity().managedQuery(u, projection, selection, null, imageOrderBy);
        if(null != c && c.moveToFirst()){
            ContentResolver cr = getActivity().getContentResolver();
            cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    BaseColumns._ID + "=" + c.getString(3), null);
        }
于 2015-01-22T11:53:17.147 に答える
1

ここを見てくださいEXTRA_OUTPUT-これは、画像をギャラリーに保存せずにフォルダに保存するコードです。このように、私のアプリケーションでは、カメラから直接写真を取得してから、撮影した写真を削除していました。

于 2011-06-23T05:02:54.930 に答える
1

これは私が使用するコードで、写真を撮り、指定された場所に保存します

Uri outputFileUri;

public void takePhoto() {
    File directory = new File(Environment.getExternalStorageDirectory()
            + "/HI-Tech" + "/");

    if (!directory.exists()) {
        directory.mkdir();
    }

    int count = 0;
    if (directory != null) {
        File[] files = directory.listFiles();
        if (files != null) {
            count = files.length;
        }
    }
    count++;
    String imagePath = "IMAGE_" + count + ".jpg";
    File file = new File(directory, imagePath);
    outputFileUri = Uri.fromFile(file);

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(intent, JobActivity.TAKE_PIC);
}

次に、応答を処理します。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    try {
        if (resultCode == RESULT_OK) {
            if (requestCode == JobActivity.TAKE_PIC) {
                Bitmap bitmap = decodeFile(new File(outputFileUri.getPath()), 160, 120);
    } catch (Exception e) {
        Log.e("Error", "Unable to set thumbnail", e);
    }
}

保存されたパスonActivityResultを取得する方法が見つからなかったため、outputFileUriをグローバル変数として宣言する必要がありました。outputFileUriを渡すと、画像がカメラフォールドではなく、指定された場所に保存されていることがわかります。私はNexus1と安いサムスンのものでこのコードを試しました。

お役に立てれば

于 2011-06-23T23:44:28.180 に答える
1

私もこの問題に苦しんでいました。ちなみに、この問題はObsoleteAndroidバグトラッカーのようにマークされています。何らかの理由で、Androidチームはこれをバグとは見なしていません。おそらくこれはメーカー関連だからです。

すべてのソリューション(このスレッドや他のブログ投稿などから)は、次のアルゴリズムを形成しているようです。

  1. 最後に撮影した写真の一意の識別子を保存します。
  2. ;を使用Intentしてカメラアクティビティを起動します。EXTRA_OUTPUT
  3. 写真を撮り、ギャラリーで最後に撮った写真のIDが変更されているかどうかを確認して、削除するかどうかを決定します。

受け入れられた回答では、同様のことが提案されています。

しかし、そのようなアプローチは実稼働コードでは使用できないことがわかりました。たとえば、簡単な状況を想像してみましょう。

最後に撮影した写真のIDをギャラリーに保存し、カメラアクティビティを起動します。ユーザーが一部のデバイスで写真を撮ると、カメラアクティビティCancelOKボタン(またはそのようなもの)が付いたダイアログが表示されます。そして、その背後にあるロジックは次のとおりです。

  • ユーザーがを押すCancelと、カメラアクティビティに戻り、写真を撮り続けることができます。
  • 彼/彼女(ユーザー)がOKボタンを押すと、カメラアクティビティは結果をアプリに返します。

ここでの重要な注意事項:一部のデバイス(LGとHTCでテスト)では、このダイアログが表示されている間、画像はすでに保存されている可能性があります。

ここで、ユーザーが何らかの理由でHomeボタンをタップして別のアプリを起動した場合を想像してみてください(たとえば、ユーザーが別の写真を撮ることができる別のカメラアプリ!)。次に、そのダイアログが表示されたままアプリに戻り、を押しOKます。明らかにその場合、あなたのアプリは間違ったファイルを削除します...そしてユーザーを失望させます:(

したがって、多くの調査の結果、この問題を克服するための最善のアプローチは、独自のカメラエンジンを作成するか、次のようなサードパーティのライブラリを使用することであると判断しました:マテリアルカメラ

于 2016-11-08T19:24:02.880 に答える
0

最善の策は、Cameraクラスを直接処理してから、返されたjpegまたはrawをコールバックで必要な場所に保存することです。

または、追加した後、メディアのコンテンツプロバイダーから_idで撮影した画像を削除してみることもできます。クエリで見つけてContentResolver.deleteで削除するだけですが、実装についてはわかりません。

于 2011-06-27T21:54:01.930 に答える
0

しばらくこれに苦労した後、私は弾丸を噛み、自分のカメラキャプターアクティビティを書きました。私は、これがソリューションよりもはるかにポータブルで安全であると確信していMediaStore.ACTION_IMAGE_CAPTUREます。画像は保存した場所に保存され、他の場所には保存されません。誤って無関係なファイルを削除する危険はありません。また、実際のカメラ機能を要件に正確に適合させることも可能です。

移植性の理由から、Cameracamera2ではなくクラスを使用しました。

カメラのパラメータ、特に画像サイズ、フォーカスモード、フラッシュモードをすべて設定する必要があることに注意してください。これらはすべて、カメラの起動時に予期しない状態になる可能性があります。

これをコメントとしてではなく回答として投稿するのは、私の意見では正解であり、最小限の労力で済むからです。

于 2017-03-15T11:42:51.443 に答える
0
protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {

    Bitmap photo = (Bitmap) data.getExtras().get("data");
    Uri tempUri = Utils.getUri(getActivity(), photo);
    File finalFile = new File(getRealPathFromURI(tempUri));
    finalFile.delete();
    }  
}


public String getRealPathFromURI (Uri contentUri) {
    String path = null;
    String[] proj = { MediaStore.MediaColumns.DATA };
    Cursor cursor = getActivity().getContentResolver().query(contentUri, proj, null, null, null);
    if (cursor.moveToFirst()) {
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
        path = cursor.getString(column_index);
    }
    cursor.close();
    return path;
}
于 2018-04-16T12:23:44.313 に答える
0

以下のコードは、画像ファイルを削除するだけでなく、filwが削除されたときに残される0Byteファイルも削除します。この0Byteゴーストファイルの動作をAndroid10で観察しました。

    val fileToDelete = File(photoUri.path)
    if (fileToDelete.exists()) {
        if (fileToDelete.delete()) {
            if (fileToDelete.exists()) {
                fileToDelete.canonicalFile.delete()
                if (fileToDelete.exists()) {
                    getApplicationContext().deleteFile(fileToDelete.name)
                }
            }
            Log.e("File", "Deleted " + savedPhotoUri?.path)
        } else {
            Log.e("File", "not Deleted " + savedPhotoUri?.path)
        }
    }
于 2020-04-17T11:27:41.587 に答える