web-dev-qa-db-ja.com

IllegalArgumentException:列 '_data'は存在しません

Nougatでは、この機能は機能していません。

String path = getRealPathFromURI(this, getIntent().getParcelableExtra(Intent.EXTRA_STREAM));


public String getRealPathFromURI(Context context, Uri contentUri) {
    Cursor cursor = null;
    try {
        String[] proj = {MediaStore.Images.Media.DATA};
        cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        if (cursor == null) return contentUri.getPath();
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

クラッシュログ:

Java.lang.RuntimeException: Unable to start activity ComponentInfo{class path}: Java.lang.IllegalArgumentException: column '_data' does not exist
   at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2659)
   at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2724)
   at Android.app.ActivityThread.-wrap12(ActivityThread.Java)
   at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1473)
   at Android.os.Handler.dispatchMessage(Handler.Java:102)
   at Android.os.Looper.loop(Looper.Java:154)
   at Android.app.ActivityThread.main(ActivityThread.Java:6123)
   at Java.lang.reflect.Method.invoke(Method.Java)
   at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:867)
   at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:757)
Caused by Java.lang.IllegalArgumentException: column '_data' does not exist
   at Android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.Java:333)
   at Android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.Java:87)
   at com.package.SaveImageActivity.getRealPathFromURI()
   at com.package.SaveImageActivity.onCreate()
   at Android.app.Activity.performCreate(Activity.Java:6672)
   at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1140)
   at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2612)
   at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2724)
   at Android.app.ActivityThread.-wrap12(ActivityThread.Java)
   at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1473)
   at Android.os.Handler.dispatchMessage(Handler.Java:102)
   at Android.os.Looper.loop(Looper.Java:154)
   at Android.app.ActivityThread.main(ActivityThread.Java:6123)
   at Java.lang.reflect.Method.invoke(Method.Java)
   at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:867)
   at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:757)

この関数は、デバイスでAndroid Nの前に正常に機能しています。記事を読みました file://スキームはtargetSdkVersion 24のIntentでアタッチできません。 (Android Nougat) 。しかし、解決策が見つかりませんでした。

22
vidha

この関数は、デバイスでAndroid N

ごく少数のUri値で機能し、結果が得られない場合があります(たとえば、ローカルファイルではないMediaStoreによってインデックス付けされたものの場合)、使用可能な結果がない場合があります(たとえば、リムーバブルストレージ上のファイルの場合)。

だから助けてください。

ContentResolveropenInputStream()を使用して、InputStreamで識別されるコンテンツでUriを取得します。理想的には、あなたがやろうとしていることに関係なく、そのストリームを直接使用するだけです。または、制御するファイルでそのInputStreamといくつかのFileOutputStreamを使用してコンテンツのコピーを作成し、そのファイルを使用します。

26
CommonsWare

CommonsWareの回答によると、ソリューションコードは次のとおりです。

public static String getFilePathFromURI(Context context, Uri contentUri) {
    //copy file and send new file path 
    String fileName = getFileName(contentUri);
    if (!TextUtils.isEmpty(fileName)) {
        File copyFile = new File(TEMP_DIR_PATH + File.separator + fileName);
        copy(context, contentUri, copyFile);
        return copyFile.getAbsolutePath();
    }
    return null;
}

public static String getFileName(Uri uri) {
    if (uri == null) return null;
    String fileName = null;
    String path = uri.getPath();
    int cut = path.lastIndexOf('/');
    if (cut != -1) {
        fileName = path.substring(cut + 1);
    }
    return fileName;
}

public static void copy(Context context, Uri srcUri, File dstFile) {
    try {
        InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
        if (inputStream == null) return;
        OutputStream outputStream = new FileOutputStream(dstFile);
        IOUtils.copyStream(inputStream, outputStream);
        inputStream.close();
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

これがあなたのお役に立てば幸いです。

IOUtils.copyの起源はこのサイトからです: https://www.developerfeed.com/copy-bytes-inputstream-outputstream-Android/ (例外を少し変更する必要があるかもしれませんが、必要に応じて機能します)

34
vidha

// Android N:

private static String getFilePathForN(Uri uri, Context context) {
    Uri returnUri = uri;
    Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null);
    /*
     * Get the column indexes of the data in the Cursor,
     *     * move to the first row in the Cursor, get the data,
     *     * and display it.
     * */
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
    returnCursor.moveToFirst();
    String name = (returnCursor.getString(nameIndex));
    String size = (Long.toString(returnCursor.getLong(sizeIndex)));
    File file = new File(context.getFilesDir(), name);
    try {
        InputStream inputStream = context.getContentResolver().openInputStream(uri);
        FileOutputStream outputStream = new FileOutputStream(file);
        int read = 0;
        int maxBufferSize = 1 * 1024 * 1024;
        int bytesAvailable = inputStream.available();

        //int bufferSize = 1024;
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);

        final byte[] buffers = new byte[bufferSize];
        while ((read = inputStream.read(buffers)) != -1) {
            outputStream.write(buffers, 0, read);
        }
        Log.e("File Size", "Size " + file.length());
        inputStream.close();
        outputStream.close();
        Log.e("File Path", "Path " + file.getPath());
        Log.e("File Size", "Size " + file.length());
    } catch (Exception e) {
        Log.e("Exception", e.getMessage());
    }
    return file.getPath();
}
3
satyawan hajare

@Redturboコメントを書くことができません。ここに書きます

IOUtils.copyStream(inputStream, outputStream);

TEMP_DIR_PATH-任意のディレクトリパス、次のようなもの

 File rootDataDir = context.getFilesDir();
 File copyFile = new File( rootDataDir + File.separator + fileName + ".jpg");
2
kalmahik