手记

Android 相册图片资源选择器URI路径问题

最近在做项目的时候发现以前做好的东西报错了,这还得了,一看,原来是相册中获取图片的是从SQLite里面取数据的时候图片过大了,就直接返回-1,最后还是Google上面找到了答案,

最近在做项目的时候发现以前做好的东西报错了,这还得了,一看,原来是相册中获取图片的是从SQLite里面取数据的时候图片过大了,就直接返回-1,最后还是Google上面找到了答案,

先看一下错误,刚开始看的时候以为是数据查询的错误,但后面看代码的时候才找到问题的根源所在


E/AndroidRuntime: FATAL EXCEPTION: main
                   Process: com.chongxin.app, PID: 3534
                   java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { dat=content://com.android.providers.media.documents/document/image:3195 flg=0x1 }} to activity {com.chongxin.app/com.chongxin.app.activity.yelj.NewChatActivity}: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
                   at android.app.ActivityThread.deliverResults(ActivityThread.java:3574)
                   at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
                   at android.app.ActivityThread.access$1300(ActivityThread.java:151)
                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
                   at android.os.Handler.dispatchMessage(Handler.java:102)
                   at android.os.Looper.loop(Looper.java:135)
                   at android.app.ActivityThread.main(ActivityThread.java:5254)
                   at java.lang.reflect.Method.invoke(Native Method)
                   at java.lang.reflect.Method.invoke(Method.java:372)
                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
         Caused by: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
                   at android.database.CursorWindow.nativeGetString(Native Method)
                   at android.database.CursorWindow.getString(CursorWindow.java:438)
                   at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
                   at android.database.CursorWrapper.getString(CursorWrapper.java:114)
                   at com.avoscloud.chat.contrib.ui.activity.MyChatActivity.parsePathByReturnData(MyChatActivity.java:673)
                   at com.avoscloud.chat.contrib.ui.activity.MyChatActivity.onActivityResult(MyChatActivity.java:686)
                   at android.app.Activity.dispatchActivityResult(Activity.java:6192)
                   at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
                   at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)?
                   at android.app.ActivityThread.access$1300(ActivityThread.java:151)?
                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)?
                   at android.os.Handler.dispatchMessage(Handler.java:102)?
                   at android.os.Looper.loop(Looper.java:135)?
                   at android.app.ActivityThread.main(ActivityThread.java:5254)?
                   at java.lang.reflect.Method.invoke(Native Method)?
                   at java.lang.reflect.Method.invoke(Method.java:372)?
                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)?
                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)


一般出现这样情况的时候的时候说明APP已经蹦了(这不废话吗,不着急,先凑点字数,各位先见谅哈)!!!!

而且出现这样的情况的时候主要是在相册图片选择的时候图片过大,(Google出来的)原来是数据库的读取中出现了问题,Cursor对象只能够存储1MB的数据(网上有人说是1MB),多了会发生这样的报错。我之前从相册选取照片有时成功有时失败的问题,我猜想可能是选取了大于1MB的图片和小于1MB的图片的问题,为了验证这个猜想我准备了两张不同大小的照片,果然在选取小的那张时就成功了,大的系统就崩溃了。

问题大致上是一样的,解决的方法不同,有兴趣的同学可以看看 :http://blog.csdn.net/wjilikely/article/details/79542824

我先把出问题的地方贴出来:

   
    /**
     * 通过返回数据解析路径
     *
     * @param data
     * @return
     */
    private String parsePathByReturnData(Intent data) {
        if (data == null) {
            return null;
        }
        String localSelectPath = null;
        Uri selectedImage = data.getData();
        if (selectedImage != null) {
            
            Cursor cursor = getContentResolver().query(selectedImage, null, null, null, null);
            if (cursor.moveToFirst() && cursor != null) {
               		int columnIndex = cursor.getColumnIndex("_data");//图片过大的时候会返回 -1
               		localSelectPath = cursor.getString(columnIndex);//获取到的路径为空,或者就直接崩掉
          }
	            	cursor.close();

        }
        return localSelectPath;
    }

   

就是我标明红色字体的两行代码,正常的情况下cursor.getColumnIndex("_data")会返回图片的索引,就可以直接获取到

图片信息正常显示了,但是出现错误的时候返回的图片信息为空,返回的时候也会报错(不是这个错,会报空异常,所以还是这个问题引起的)

问题分析解决:

   在选择图片小的加载成功了,那就说明只要把图片压缩不就解决问题了吗,对,就是这样简单。

/**
     * 通过返回数据解析路径
     *
     * @param data
     * @return
     */
    private String parsePathByReturnData(Intent data) {
        if (data == null) {
            return null;
        }
        String localSelectPath = null;
        Uri selectedImage = data.getData();
        if (selectedImage != null) {
            //防止图片过的时候崩溃
            localSelectPath = VideoSelect.getPath(MyChatActivity.this, selectedImage);//把图片压缩后再赋值(防止图片过大崩溃)

        }
        return localSelectPath;
    }

再加一个图片压缩处理类VideoSelect,基本就就解决问题了

/**
     * 通过返回数据解析路径
     *
     * @param data
     * @return
     */
    private String parsePathByReturnData(Intent data) {
        if (data == null) {
            return null;
        }
        String localSelectPath = null;
        Uri selectedImage = data.getData();
        if (selectedImage != null) {
            
            Cursor cursor = getContentResolver().query(selectedImage, null, null, null, null);
            if (cursor.moveToFirst() && cursor != null) {
               	int columnIndex = cursor.getColumnIndex("_data");//图片过大的时候会返回 -1
               		localSelectPath = cursor.getString(columnIndex);//获取到的路径为空,或者就直接崩掉
          }
	            	cursor.close();
        }
        return localSelectPath;
    }

package com.avoscloud.chat.contrib.util;

import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

/**
 * Created by Tomz on 2018/3/13 0013.
 */

public class VideoSelect {
    /**
     * 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.
     *
     * @param context The context.
     * @param uri The Uri to query.
     * @author paulburke
     */
    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 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;
    }


    /**
     * @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());
    }
}

最后,问题完美的解决了,当然,压缩的时候不要太狠,不然会失真的

原文链接:http://www.apkbus.com/blog-651242-77230.html

0人推荐
随时随地看视频
慕课网APP