获取从图库中选择的图像的路径(在 SD 卡上)
Get path to image chosen from gallery(on SD card)
我根本无法获取从 SD 卡上的图库中选择的图像的路径,但存储在设备上的图像没有问题。有许多类似或重复的问题,但其中 none 有效。
最推荐的方法(@Commonsware)是使用 ContentResolver
并调用 openInputStream()
,所以我尝试从 openInputStream()
读取字节,然后创建一个临时文件并使用那条路,没有运气。我的 "bytes read: " System.err.println
调用显示读取了 0 个字节。
我也尝试过this, , this, this, this, and this、none的工作。许多这些答案导致调用 BitmapFactory#decodeStream()
,问题是,我不关心显示图像,我只需要路径!!
请帮忙!
目前代码:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK){
switch(requestCode){
case SELECT_FROM_GALLERY:
fromGallery = true;
path = getRealPathFromURI(data.getData());
System.err.println("*******path: " + path + "*********");
break;
}
}
}
public String getRealPathFromURI(Uri contentUri) {
String thePath = null;
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContext().getContentResolver().query(contentUri, filePathColumn, null, null, null);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
thePath = cursor.getString(columnIndex);
}
cursor.close();
if(thePath == null){
return getImagePathExternal(contentUri);
}else {
return thePath;
}
}
public String getImagePathExternal(Uri uri){
Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":")+1);
cursor.close();
cursor = getContext().getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
if(path == null){
System.err.println("****************trying bytes route******************");
try{
InputStream in = getContext().getContentResolver().openInputStream(uri);
byte[] resultBuff = new byte[0];
byte[] buff = new byte[1024];
int k ;
while((k = in.read(buff, 0, buff.length)) > -1) {
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
}
System.err.println("****************bytes read: "+resultBuff.length+" ******************");
File tem = new File(_tempImageDir, "temp.jpg");
FileOutputStream out = new FileOutputStream(tem);
out.write(resultBuff, 0, resultBuff.length);
return tem.getAbsolutePath();
}catch(Exception e){
e.printStackTrace();
return null;
}
}
return path;
}
Logcat(这个异常永远不会改变,无论我使用哪种方法):
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.venon.nakomangsp, PID: 20610
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=132074, result=-1, data=Intent { dat=content://media/external/images/media/4147 (has extras) }} to activity {com.venon.nakomangsp/com.venon.nakomangsp.SignUpActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4058)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101)
at android.app.ActivityThread.access00(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at id.zelory.compressor.ImageUtil.getScaledBitmap(ImageUtil.java:62)
at id.zelory.compressor.ImageUtil.compressImage(ImageUtil.java:161)
at id.zelory.compressor.Compressor.compressToFile(Compressor.java:48)
at com.venon.nakomangsp.SignUpFragment.preparePicture(SignUpFragment.java:870)
at com.venon.nakomangsp.SignUpFragment.onActivityResult(SignUpFragment.java:783)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
at com.venon.nakomangsp.SignUpActivity.onActivityResult(SignUpActivity.java:37)
at android.app.Activity.dispatchActivityResult(Activity.java:6549)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4054)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101)
at android.app.ActivityThread.access00(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
如果你使用的是API24,那么你应该使用FileProvide,介绍的官网:https://developer.android.com/reference/android/support/v4/content/FileProvider.html
你应该这样写:
在XML中指定一个存储区域和路径的内容,使用元素的子元素。例如,下面的 pathsmann 告诉 FileProvider 您打算为您的私有文件区域的图像/子目录请求内容 URI。
<Manifest>
<Application>
<Provider
Android: name = "android.support.v4.content.FileProvider"
Android: authorities = "com.mydomain.fileprovider"
Android: exported = "false"
Android: grantUriPermissions = "true"
<Meta-data
Android: name = "android.support.FILE_PROVIDER_PATHS"
Android: resource = "@ xml / file_paths" />
</ Provider>
</ Application>
</ Manifest>
<? Xml version = "1.0" encoding = "utf-8"?>
<Resources>
<Paths>
<External-path
Name = "external_files"
Path = "." />
<Root-path
Name = "external_files"
Path = "/ storage /" />
</ Paths> `enter code here`
</ Resources>
第三步:文件就是你的路径
Uri contentUri = getUriForFile (getContext (), getPackageName () + ".provider", file);
应用程序无法直接访问 SD 卡中的任何内容。因此,即使您可以获得某种 'path',您的应用程序也无法从该位置读取任何内容。
可靠地访问这些文件内容的唯一方法是通过 ContentResolver.openInputStream()(或者其他 open
方法,如果您需要 AssetFileDescriptor
,等等)。
您绝对可以将文件复制到您的 own cache directory,然后对图像进行任何您想做的事情。
不同的手机有一些不同的行为。经过大量研究并尝试不同的可能性后,我想出了一个解决方案,该解决方案适用于我测试过的所有手机 (LG G2、Nexus 5、ZTE、Note 5、Nexus 6、Infinix Note 3 Pro 和其他一些我不记得了)。如果有效,请尝试此操作。根据自己的需要服用。它还包括从相机捕获图片,复制它并获取它的路径。
//SELECT PICTURE FROM GALLERY OR CAPTURE FROM CAMERA
private void selectPicture(View view) {
tempView = view;
final CharSequence[] items;
if(view.getClass().getName().equalsIgnoreCase("android.widget.ImageView"))
items = new CharSequence[]{ "Take Photo", "Choose from Library", "Remove Photo", "Cancel" };
else items = new CharSequence[]{ "Take Photo", "Choose from Library", "Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(ActivityAddMemory.this);
builder.setTitle("Add Image");
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
if (items[item].equals("Take Photo")) {
showCamera();
} else if (items[item].equals("Choose from Library")) {
Intent intent = new Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(
Intent.createChooser(intent, "Select File"),
SELECT_FILE);
} else if(items[item].equals("Remove Photo")) {
imgLinearLayout.removeView(tempView);
imagesList.remove(tempView.getId());
if(imagesList.size() < 1) {
imgLinearLayout.setVisibility(View.GONE);
}
if(btnAddPhoto.getVisibility() == View.GONE)
btnAddPhoto.setVisibility(View.VISIBLE);
} else if (items[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
//OPEN CAMERA IF WANT TO CAPTURE
private void showCamera() {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "DCIM");
if (!file.exists()) {
file.mkdirs();
}
File localFile2 = new File(file + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
imageUri = Uri.fromFile(localFile2);
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
cameraIntent.setClipData(ClipData.newRawUri(null, Uri.fromFile(localFile2)));
}
startActivityForResult(cameraIntent, REQUEST_CAMERA);
} catch (Exception localException) {
Toast.makeText(ActivityAddMemory.this, "Exception:" + localException, Toast.LENGTH_SHORT).show();
}
}
//GET PATH FROM URI IF SELECTED FROM GALLERY
public String getRealPathFromURI(Uri uri){
String filePath = "";
String[] filePahColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, filePahColumn, null, null, null);
if (cursor != null) {
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(filePahColumn[0]);
filePath = cursor.getString(columnIndex);
}
cursor.close();
}
return filePath;
}
//DO WHAT YOU WANT WHEN RESULT IS RETURNED
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode == RESULT_OK) {
String path=null;
Uri uri;
if (intent == null || intent.getData() == null)
uri = this.imageUri;
else
uri = intent.getData();
if(requestCode == SELECT_FILE) {
path = getRealPathFromURI(uri);
} else if(requestCode == REQUEST_CAMERA){
path = uri.getEncodedPath();
}
//THIS IS THE PATH YOU WOULD NEED
}
}
我根本无法获取从 SD 卡上的图库中选择的图像的路径,但存储在设备上的图像没有问题。有许多类似或重复的问题,但其中 none 有效。
最推荐的方法(@Commonsware)是使用 ContentResolver
并调用 openInputStream()
,所以我尝试从 openInputStream()
读取字节,然后创建一个临时文件并使用那条路,没有运气。我的 "bytes read: " System.err.println
调用显示读取了 0 个字节。
我也尝试过this, BitmapFactory#decodeStream()
,问题是,我不关心显示图像,我只需要路径!!
请帮忙!
目前代码:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK){
switch(requestCode){
case SELECT_FROM_GALLERY:
fromGallery = true;
path = getRealPathFromURI(data.getData());
System.err.println("*******path: " + path + "*********");
break;
}
}
}
public String getRealPathFromURI(Uri contentUri) {
String thePath = null;
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContext().getContentResolver().query(contentUri, filePathColumn, null, null, null);
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
thePath = cursor.getString(columnIndex);
}
cursor.close();
if(thePath == null){
return getImagePathExternal(contentUri);
}else {
return thePath;
}
}
public String getImagePathExternal(Uri uri){
Cursor cursor = getContext().getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":")+1);
cursor.close();
cursor = getContext().getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
if(path == null){
System.err.println("****************trying bytes route******************");
try{
InputStream in = getContext().getContentResolver().openInputStream(uri);
byte[] resultBuff = new byte[0];
byte[] buff = new byte[1024];
int k ;
while((k = in.read(buff, 0, buff.length)) > -1) {
byte[] tbuff = new byte[resultBuff.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(resultBuff, 0, tbuff, 0, resultBuff.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, resultBuff.length, k); // copy current lot
resultBuff = tbuff; // call the temp buffer as your result buff
}
System.err.println("****************bytes read: "+resultBuff.length+" ******************");
File tem = new File(_tempImageDir, "temp.jpg");
FileOutputStream out = new FileOutputStream(tem);
out.write(resultBuff, 0, resultBuff.length);
return tem.getAbsolutePath();
}catch(Exception e){
e.printStackTrace();
return null;
}
}
return path;
}
Logcat(这个异常永远不会改变,无论我使用哪种方法):
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.venon.nakomangsp, PID: 20610
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=132074, result=-1, data=Intent { dat=content://media/external/images/media/4147 (has extras) }} to activity {com.venon.nakomangsp/com.venon.nakomangsp.SignUpActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4058)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101)
at android.app.ActivityThread.access00(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
at id.zelory.compressor.ImageUtil.getScaledBitmap(ImageUtil.java:62)
at id.zelory.compressor.ImageUtil.compressImage(ImageUtil.java:161)
at id.zelory.compressor.Compressor.compressToFile(Compressor.java:48)
at com.venon.nakomangsp.SignUpFragment.preparePicture(SignUpFragment.java:870)
at com.venon.nakomangsp.SignUpFragment.onActivityResult(SignUpFragment.java:783)
at android.support.v4.app.FragmentActivity.onActivityResult(FragmentActivity.java:165)
at com.venon.nakomangsp.SignUpActivity.onActivityResult(SignUpActivity.java:37)
at android.app.Activity.dispatchActivityResult(Activity.java:6549)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4054)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4101)
at android.app.ActivityThread.access00(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1497)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
如果你使用的是API24,那么你应该使用FileProvide,介绍的官网:https://developer.android.com/reference/android/support/v4/content/FileProvider.html 你应该这样写:
在XML中指定一个存储区域和路径的内容,使用元素的子元素。例如,下面的 pathsmann 告诉 FileProvider 您打算为您的私有文件区域的图像/子目录请求内容 URI。
<Manifest> <Application> <Provider Android: name = "android.support.v4.content.FileProvider" Android: authorities = "com.mydomain.fileprovider" Android: exported = "false" Android: grantUriPermissions = "true" <Meta-data Android: name = "android.support.FILE_PROVIDER_PATHS" Android: resource = "@ xml / file_paths" /> </ Provider> </ Application> </ Manifest> <? Xml version = "1.0" encoding = "utf-8"?> <Resources> <Paths> <External-path Name = "external_files" Path = "." /> <Root-path Name = "external_files" Path = "/ storage /" /> </ Paths> `enter code here` </ Resources>
第三步:文件就是你的路径
Uri contentUri = getUriForFile (getContext (), getPackageName () + ".provider", file);
应用程序无法直接访问 SD 卡中的任何内容。因此,即使您可以获得某种 'path',您的应用程序也无法从该位置读取任何内容。
可靠地访问这些文件内容的唯一方法是通过 ContentResolver.openInputStream()(或者其他 open
方法,如果您需要 AssetFileDescriptor
,等等)。
您绝对可以将文件复制到您的 own cache directory,然后对图像进行任何您想做的事情。
不同的手机有一些不同的行为。经过大量研究并尝试不同的可能性后,我想出了一个解决方案,该解决方案适用于我测试过的所有手机 (LG G2、Nexus 5、ZTE、Note 5、Nexus 6、Infinix Note 3 Pro 和其他一些我不记得了)。如果有效,请尝试此操作。根据自己的需要服用。它还包括从相机捕获图片,复制它并获取它的路径。
//SELECT PICTURE FROM GALLERY OR CAPTURE FROM CAMERA
private void selectPicture(View view) {
tempView = view;
final CharSequence[] items;
if(view.getClass().getName().equalsIgnoreCase("android.widget.ImageView"))
items = new CharSequence[]{ "Take Photo", "Choose from Library", "Remove Photo", "Cancel" };
else items = new CharSequence[]{ "Take Photo", "Choose from Library", "Cancel" };
AlertDialog.Builder builder = new AlertDialog.Builder(ActivityAddMemory.this);
builder.setTitle("Add Image");
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
if (items[item].equals("Take Photo")) {
showCamera();
} else if (items[item].equals("Choose from Library")) {
Intent intent = new Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(
Intent.createChooser(intent, "Select File"),
SELECT_FILE);
} else if(items[item].equals("Remove Photo")) {
imgLinearLayout.removeView(tempView);
imagesList.remove(tempView.getId());
if(imagesList.size() < 1) {
imgLinearLayout.setVisibility(View.GONE);
}
if(btnAddPhoto.getVisibility() == View.GONE)
btnAddPhoto.setVisibility(View.VISIBLE);
} else if (items[item].equals("Cancel")) {
dialog.dismiss();
}
}
});
builder.show();
}
//OPEN CAMERA IF WANT TO CAPTURE
private void showCamera() {
try {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "DCIM");
if (!file.exists()) {
file.mkdirs();
}
File localFile2 = new File(file + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
imageUri = Uri.fromFile(localFile2);
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
cameraIntent.setClipData(ClipData.newRawUri(null, Uri.fromFile(localFile2)));
}
startActivityForResult(cameraIntent, REQUEST_CAMERA);
} catch (Exception localException) {
Toast.makeText(ActivityAddMemory.this, "Exception:" + localException, Toast.LENGTH_SHORT).show();
}
}
//GET PATH FROM URI IF SELECTED FROM GALLERY
public String getRealPathFromURI(Uri uri){
String filePath = "";
String[] filePahColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, filePahColumn, null, null, null);
if (cursor != null) {
if(cursor.moveToFirst()){
int columnIndex = cursor.getColumnIndex(filePahColumn[0]);
filePath = cursor.getString(columnIndex);
}
cursor.close();
}
return filePath;
}
//DO WHAT YOU WANT WHEN RESULT IS RETURNED
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode == RESULT_OK) {
String path=null;
Uri uri;
if (intent == null || intent.getData() == null)
uri = this.imageUri;
else
uri = intent.getData();
if(requestCode == SELECT_FILE) {
path = getRealPathFromURI(uri);
} else if(requestCode == REQUEST_CAMERA){
path = uri.getEncodedPath();
}
//THIS IS THE PATH YOU WOULD NEED
}
}