Не удается загрузить фотографию с камеры на сервер.IllegalArgumentException: столбец '_data' не существует - PullRequest
0 голосов
/ 16 мая 2018

Я не могу отправить фотографии, сделанные с камеры, на сервер.Я следовал документам Google по пошаговой съемке фотографий (https://developer.android.com/training/camera/photobasics)), но все еще не могу сделать это. Загрузка файлов из галереи устройств, кажется, работает нормально. Также, если я записываю видео, загрузка будет успешной.

Это мой код активности:

private static int REQUEST_IMAGE_CAPTURE = 2;

private String mCurrentPhotoPath;

private Uri photoUri;

private List<File> filesArray;
private List<Uri> filesUrisArray;
private List<String> mimeTypesArray;

// Camera Intent
public void takePhoto() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // Create the File where the photo should go
            File photoFile = null;
            photoUri = null;
            try {
                photoFile = createImageFile();
                photoUri = FileProvider.getUriForFile(this, "com.company.name.appname.provider", photoFile);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            // Continue only if the File was successfully created
            if (photoUri != null) {
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
            }
        }
    }
@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode){
            case 2:
                if (resultCode == RESULT_OK) {
                    try {
                        galleryAddPic();
                        filesUrisArray.set(selectedMedia, photoUri);
                        mimeTypesArray.set(selectedMedia, getContentResolver().getType(photoUri));
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
                break;
        }

    }
/**
 * Add the photo to gallery
 */
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}
 /**
 * Method to create image file name (usado cuando sacas fotos con la cámara)
 */
private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "PNG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".png",    /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = image.getAbsolutePath();

    return image;
}

Поставщик файлов:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

Конфигурация поставщика файлов в моем манифесте Android:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.company.name.appname.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

Проблема заключается в том, что когда я пытаюсь подготовить файл для отправки на сервер, он выдает следующее исключение:

Caused by: java.lang.IllegalArgumentException: column '_data' does not exist. Available columns: []
        at android.database.AbstractCursor.getColumnIndexOrThrow(AbstractCursor.java:340)
        at android.database.CursorWrapper.getColumnIndexOrThrow(CursorWrapper.java:87)
        at com.company.name.appname.comun.utils.FileUtils.getDataColumn(FileUtils.java:231)
        at com.company.name.appname.comun.utils.FileUtils.getPath(FileUtils.java:329)
        at com.company.name.appname.comun.utils.FileUtils.getFile(FileUtils.java:349)

Uri фотографии выглядит так: content: // com.company.name.appname.provider / external_files / Android / data / com.company.name.appname / files / Pictures / PNG_20180516_105223_8084097384330493776.png

Здесь происходит сбой моего приложения при вызове метода FileUtils.getFile:

@NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {  
    File file = FileUtils.getFile(this, fileUri);

    RequestBody requestFile =
        RequestBody.create(
            MediaType.parse(getContentResolver().getType(fileUri)), 
            file
        );

    return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}   

Класс FileUtils (исключение вызвано методом getDataColumn):

 /**
 * Convert Uri into File, if possible.
 *
 * @return file A local file that the Uri was pointing to, or null if the
 *         Uri is unsupported or pointed to a remote resource.
 * @see #getPath(Context, Uri)
 * @author paulburke
 */
public static File getFile(Context context, Uri uri) {
    if (uri != null) {
        String path = getPath(context, uri);
        if (path != null && isLocal(path)) {
            return new File(path);
        }
    }
    return null;
}
 /**
 * Get a file path from a Uri. This will get the the path for Storage Access
 * Framework Documents, as well as the _data field for the MediaStore and
 * other file-based ContentProviders.<br>
 * <br>
 * Callers should check whether the path is local before assuming it
 * represents a local file.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @see #isLocal(String)
 * @see #getFile(Context, Uri)
 * @author paulburke
 */
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {

    if (DEBUG)
        Log.d(TAG + " File -",
                "Authority: " + uri.getAuthority() +
                        ", Fragment: " + uri.getFragment() +
                        ", Port: " + uri.getPort() +
                        ", Query: " + uri.getQuery() +
                        ", Scheme: " + uri.getScheme() +
                        ", Host: " + uri.getHost() +
                        ", Segments: " + uri.getPathSegments().toString()
        );

    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // LocalStorageProvider
        if (isLocalStorageDocument(uri)) {
            // The path is the id
            return DocumentsContract.getDocumentId(uri);
        }
        // ExternalStorageProvider
        else if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }

            // TODO handle non-primary volumes
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {

            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[] {
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {

        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}
 /**
 * Get the value of the data column for this Uri. This is useful for
 * MediaStore Uris, and other file-based ContentProviders.
 *
 * @param context The context.
 * @param uri The Uri to query.
 * @param selection (Optional) Filter used in the query.
 * @param selectionArgs (Optional) Selection arguments used in the query.
 * @return The value of the _data column, which is typically a file path.
 * @author paulburke
 */
public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {

    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            if (DEBUG)
                DatabaseUtils.dumpCursor(cursor);

            // THIS IS WHERE THE CRASH OCCURS
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

1 Ответ

0 голосов
/ 16 мая 2018

Избавьтесь от этого пронизанного ошибками метода getPath().Uri не обязательно должен иметь путь к файловой системе, не говоря уже о том, который вы можете получить.

Что более важно, вам не нужен этот метод.mCurrentPhotoPath - это путь к файловой системе, который вы создали.Используйте его.

Что вам нужно делать , так это удерживать mCurrentPhotoPath (или производную информацию) при изменениях конфигурации, таких как перевод его в состояние сохраненного экземпляра Bundle.См. этот пример проекта для демонстрации того, как использовать ACTION_IMAGE_CAPTURE с EXTRA_OUTPUT и FileProvider, включая обработку изменений конфигурации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...