最近在做项目的时候发现以前做好的东西报错了,这还得了,一看,原来是相册中获取图片的是从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的图片的问题,为了验证这个猜想我准备了两张不同大小的照片,果然在选取小的那张时就成功了,大的系统就崩溃了。
问题大致上是一样的,解决的方法不同,有兴趣的同学可以看看 :点击打开链接
我先把出问题的地方贴出来:
/**
* 通过返回数据解析路径
*
* @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());
}
}
最后,问题完美的解决了,当然,压缩的时候不要太狠,不然会失真的