最近在做项目的时候发现以前做好的东西报错了,这还得了,一看,原来是相册中获取图片的是从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()); } }
最后,问题完美的解决了,当然,压缩的时候不要太狠,不然会失真的