Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/204.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 从Picasa//Google+;同步文件夹不存在';行不通_Android_Android Intent_Android Contentprovider - Fatal编程技术网

Android 从Picasa//Google+;同步文件夹不存在';行不通

Android 从Picasa//Google+;同步文件夹不存在';行不通,android,android-intent,android-contentprovider,Android,Android Intent,Android Contentprovider,我正在尝试从gallery应用程序从Google+同步照片的一个文件夹中获取图像。选择图像后,Uri将被正确传回。但当我试图在存储设备上获取该映像的实际路径以便使用时,它崩溃了。问题似乎特别出在picasa内容提供商上 在Nexus S和Nexus 7以及其他设备上进行了测试 E/AndroidRuntime(14572): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1,

我正在尝试从gallery应用程序从Google+同步照片的一个文件夹中获取图像。选择图像后,Uri将被正确传回。但当我试图在存储设备上获取该映像的实际路径以便使用时,它崩溃了。问题似乎特别出在picasa内容提供商上

在Nexus S和Nexus 7以及其他设备上进行了测试

E/AndroidRuntime(14572): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.google.android.gallery3d.provider/picasa/item/5427003652908228690 }} E/AndroidRuntime(14572):java.lang.RuntimeException:未能传递结果ResultInfo{who=null,request=1,result=-1,data=Intent{dat=content://com.google.android.gallery3d.provider/picasa/item/5427003652908228690 }} 在这里,dat字段似乎正确地传递了Uri,但是当我试图获取图像的位置时,它崩溃了,出现以下错误

W/GalleryProvider(14381): unsupported column: _data 带GalleryProvider(14381):不支持的列:\u数据 Picasa albums的内容提供商似乎没有数据字段

获取位置的代码为:

// imageUri is the Uri from above. String[] proj = { MediaStore.Images.Media.DATA }; Cursor cursor = context.getContentResolver().query(imageUri, proj,null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String filePath = cursor.getString(column_index); cursor.close(); //imageUri是上面的Uri。 字符串[]proj={MediaStore.Images.Media.DATA}; Cursor Cursor=context.getContentResolver().query(imageUri,proj,null,null); int column_index=cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); stringfilepath=cursor.getString(列索引); cursor.close(); 此图像似乎只支持以下列: [用户帐户、picasa id、显示名称、大小、mime类型、日期、纬度、经度、方向]

我们如何获得这张图像的实际位置。如果我们不应该使用此图像,这些图像首先不应该显示给用户。

启动gallery应用程序的目的是:

Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); 意图=新意图(); intent.setType(“image/*”); intent.setAction(intent.ACTION\u GET\u CONTENT);
大约一年前我也遇到过同样的问题。。我向您展示了我的解决方案(代码非常混乱,请重构它)。 因此,您拥有从gallery返回的图像URI:

    ImageInfo getImage(URI imageUri) {

        ImageInfo result = null;

        final String[] cursorColumns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION};

        // some devices (OS versions return an URI of com.android instead of com.google.android
        if (imageUri.toString().startsWith("content://com.android.gallery3d.provider"))  {
            // use the com.google provider, not the com.android provider.
            imageUri = Uri.parse(imageUri.toString().replace("com.android.gallery3d","com.google.android.gallery3d"));
        }

        Cursor cursor = App.getContext().getContentResolver().query(imageUri, cursorColumns, null, null, null);
        if (cursor != null) {

            int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            int orientationColumnIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);

            cursor.moveToFirst();

            // if it is a picasa image on newer devices with OS 3.0 and up
            if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {

                result = new ImageInfo(downloadImage(imageUri), "0");                       

            } else { // it is a regular local image file

                result = new ImageInfo(cursor.getString(dataColumnIndex), cursor.getString(orientationColumnIndex));

            }

            cursor.close();

        } else {
            result = new ImageInfo(downloadImage(imageUri), "0");
        }

        return result;                      
}
现在我们需要下载图像的功能:

private String downloadImage(URI imageUri) {

    File cacheDir;
    // if the device has an SD card
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
        cacheDir = new File(android.os.Environment.getExternalStorageDirectory(),".OCFL311");
    } else {
        // it does not have an SD card
        cacheDir = App.getContext().getCacheDir();
    }

    if(!cacheDir.exists()) cacheDir.mkdirs();
    File f = new File(cacheDir, PUT_HERE_FILE_NAME_TO_STORE_IMAGE);

    try {

        InputStream is = null;
        if (imageUri.toString().startsWith("content://com.google.android.gallery3d")) {
            is = App.getContext().getContentResolver().openInputStream(imageUri);
        } else {
            is = new URL(imageUri.toString()).openStream();
        }

        OutputStream os = new FileOutputStream(f);
        Utils.InputToOutputStream(is, os);

        return f.getAbsolutePath();
    } catch (Exception ex) {
        Log.d(this.getClass().getName(), "Exception: " + ex.getMessage());
        // something went wrong
        ex.printStackTrace();
        return null;
    }
}
ImageInfo是用于存储图像路径及其方向的类

public static class ImageInfo {
    public final String filePath;
    public final String imageOrientation;

    public ImageInfo(String filePath, String imageOrientation) {
        this.filePath = filePath;

        if (imageOrientation == null) imageOrientation = "0";
        this.imageOrientation = imageOrientation;           
    }
}

经过大量的研究,我觉得有太多的变通方法来做一些看起来很简单的事情。所以,我继续写了一个小的库,它处理所有复杂的if-else,并且恰好适用于我能想到的所有可能的场景。试一下,看看这是否有帮助


这是一个初步的实施。虽然它可以处理几乎所有的情况,但可能会有一些bug。如果您使用此库,请让我知道您的反馈,以及是否可以进一步改进。

我现在浪费了很多时间,现在我找到了一个解决方案,它在任何情况下都可以工作,而无需在特殊线程中进行任何魔法下载或其他操作。下面的方法从用户选择的内容中返回一个流,它可以处理所有的内容

FileInputStream getSourceStream(Uri u) throws FileNotFoundException {
    FileInputStream out = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        ParcelFileDescriptor parcelFileDescriptor =
                mContext.getContentResolver().openFileDescriptor(u, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        out = new FileInputStream(fileDescriptor);
    } else {
        out = (FileInputStream) mContext.getContentResolver().openInputStream(u);
    }
    return out;
}

我用这种方法,对我来说很好, 希望这能帮助你

ACTIVITYRESULT_CHOOSEPICTURE是调用startActivity(intent,requestCode)时使用的int

如果以上代码不起作用,请参考此链接。。。它肯定会指引方向


最后以一个经典的解决方案结束…使用Document.util,它涵盖了所有权限:-1-在onActivityResult()中:-

2-创建类DocumentUtils:-

public class DocumentUtils {

@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {

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

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        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
        String url;
        if (isGooglePhotosUri(uri)) {
            url = getDataColumnWithAuthority(context, uri, null, null);
            return getDataColumn(context, Uri.parse(url), null, null);
        }

        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.
 */
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()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}
/**
 * Function for fixing synced folder image picking bug
 *
 * **/
public static String getDataColumnWithAuthority(Context context, Uri uri, String selection, String[] selectionArgs) {
    Bitmap bitmap = null;
    InputStream is = null;
    if (uri.getAuthority()!=null){
        try {
            is = context.getContentResolver().openInputStream(uri);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Bitmap bmp = BitmapFactory.decodeStream(is);
        return ImageLoader.getImageUri(context,bmp).toString();
    }

    return null;
}




/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    if(uri.getAuthority()!=null)
        return true;
    return false;
}
}

3-您还需要ImageLoader.java中的以下函数:-

public static Uri getImageUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}

下面的技巧对我很有效,我在这里做的是,如果URI中有任何权威url,那么我将使用下面的代码创建一个临时图像&返回相同的内容URI

我也回答了类似的问题


根据@drindt answer,下面的代码给出了从Google Photo cloud下载的临时
文件
路径,该路径已同步,但未在设备文件中

@SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {

    // Google photo uri example
    // content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919

    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String result = getDataColumn(context, uri, null, null); // 
        if (TextUtils.isEmpty(result))
            if (uri.getAuthority().contains("com.google.android")) {
                try {
                    File localFile = createImageFile(context, null);
                    FileInputStream remoteFile = getSourceStream(context, uri);
                    if(copyToFile(remoteFile, localFile))
                        result = localFile.getAbsolutePath();
                    remoteFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        return result;
    }
    // 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.
 */
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()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }

    return null;
}


/**
 * Copy data from a source stream to destFile.
 * Return true if succeed, return false if failed.
 */
private static boolean copyToFile(InputStream inputStream, File destFile) {
    if (inputStream == null || destFile == null) return false;
    try {
        OutputStream out = new FileOutputStream(destFile);
        try {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) >= 0) {
                out.write(buffer, 0, bytesRead);
            }
        } finally {
            out.close();
        }
        return true;
    } catch (IOException e) {
        return false;
    }
}

public static String getTimestamp() {
    try {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
    } catch (RuntimeException e) {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    }
}

public static File createImageFile(Context context, String imageFileName) throws IOException {
    if (TextUtils.isEmpty(imageFileName))
        imageFileName = getTimestamp(); // make random filename if you want.

    final File root;
    imageFileName = imageFileName;
    root = context.getExternalCacheDir();

    if (root != null && !root.exists())
        root.mkdirs();
    return new File(root, imageFileName);
}


public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
    FileInputStream out = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        ParcelFileDescriptor parcelFileDescriptor =
                context.getContentResolver().openFileDescriptor(u, "r");
        FileDescriptor fileDescriptor = null;
        if (parcelFileDescriptor != null) {
            fileDescriptor = parcelFileDescriptor.getFileDescriptor();
            out = new FileInputStream(fileDescriptor);
        }
    } else {
        out = (FileInputStream) context.getContentResolver().openInputStream(u);
    }
    return out;
}

_数据字段是图像的内容,我不认为远程图片存储在其中。您可以尝试使用uri从internet获取它。它只返回特定型号的URL。我检查了一部HTC手机,它确实给了我网址,但其他手机没有。但同样,有URL的问题是,当URL不可公开访问时。嘿,看看这个,这可能会对你有所帮助。它不会返回所有设备的URL。而且,如果URL不可公开访问,您将无法下载图像,也就是说,它不与公众共享,但只有少数人可以看到。请给我一个如何测试此情况的示例。我有Nexus7。我该怎么办?尝试附加一张属于只有你才能查看的相册的图像。是的。看来这会有用的。我会检查一下然后回来的。是的,很有效。但是,这是一个KITKAT特定的修复。如果还需要支持旧版本,则仍需要进行一些操作。不过,我对你的答案投了赞成票这不仅仅与KITKAT有关。它处理KITKAT和Older。试试看,它很管用。我们在很多设备上都这样做过,不仅仅是在更新的设备上。在三星设备和所有nexus(仿真器)上为我工作过。但是在Moto和其他两个真实设备上给出了一个“java.io.IOException:read failed:EBADF(坏文件描述符)”做得很好!我在从google+获取图像路径时遇到问题,我尝试了你的库,它工作得非常好。非常感谢你!图像选择器库不适用于gallery的picasa图像,它可以很好地将图像加载到ImageView中,但不能为上传到服务器等情况提供实际的文件路径。。
public static Uri getImageUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}
public static String getImageUrlWithAuthority(Context context, Uri uri) {
    InputStream is = null;
    if (uri.getAuthority() != null) {
        try {
            is = context.getContentResolver().openInputStream(uri);
            Bitmap bmp = BitmapFactory.decodeStream(is);
            return writeToTempImageAndGetPathUri(context, bmp).toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}
@SuppressLint("NewApi")
public static String getFilePath(final Context context, final Uri uri) {

    // Google photo uri example
    // content://com.google.android.apps.photos.contentprovider/0/1/mediakey%3A%2FAF1QipMObgoK_wDY66gu0QkMAi/ORIGINAL/NONE/114919

    if ("content".equalsIgnoreCase(uri.getScheme())) {
        String result = getDataColumn(context, uri, null, null); // 
        if (TextUtils.isEmpty(result))
            if (uri.getAuthority().contains("com.google.android")) {
                try {
                    File localFile = createImageFile(context, null);
                    FileInputStream remoteFile = getSourceStream(context, uri);
                    if(copyToFile(remoteFile, localFile))
                        result = localFile.getAbsolutePath();
                    remoteFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        return result;
    }
    // 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.
 */
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()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }

    return null;
}


/**
 * Copy data from a source stream to destFile.
 * Return true if succeed, return false if failed.
 */
private static boolean copyToFile(InputStream inputStream, File destFile) {
    if (inputStream == null || destFile == null) return false;
    try {
        OutputStream out = new FileOutputStream(destFile);
        try {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) >= 0) {
                out.write(buffer, 0, bytesRead);
            }
        } finally {
            out.close();
        }
        return true;
    } catch (IOException e) {
        return false;
    }
}

public static String getTimestamp() {
    try {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ROOT).format(new Date());
    } catch (RuntimeException e) {
        return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    }
}

public static File createImageFile(Context context, String imageFileName) throws IOException {
    if (TextUtils.isEmpty(imageFileName))
        imageFileName = getTimestamp(); // make random filename if you want.

    final File root;
    imageFileName = imageFileName;
    root = context.getExternalCacheDir();

    if (root != null && !root.exists())
        root.mkdirs();
    return new File(root, imageFileName);
}


public static FileInputStream getSourceStream(Context context, Uri u) throws FileNotFoundException {
    FileInputStream out = null;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        ParcelFileDescriptor parcelFileDescriptor =
                context.getContentResolver().openFileDescriptor(u, "r");
        FileDescriptor fileDescriptor = null;
        if (parcelFileDescriptor != null) {
            fileDescriptor = parcelFileDescriptor.getFileDescriptor();
            out = new FileInputStream(fileDescriptor);
        }
    } else {
        out = (FileInputStream) context.getContentResolver().openInputStream(u);
    }
    return out;
}