Reputation: 503
I simply CANNOT get the path to an image chosen from the gallery thats on the SD card, but there is no problem with images stored on the device. There are dozens of similar or duplicate questions like this, but none of them are working.
The most recommended approach (by @Commonsware) is to use a ContentResolver
and call openInputStream()
, so I tried reading the bytes from openInputStream()
then creating a temp file and using that path, no luck. My "bytes read: " System.err.println
call shows 0 bytes read.
I also tried this, this, this, this, this, and this, none work. A lot of these answers lead to calling BitmapFactory#decodeStream()
, problem is, I couldn't care less about displaying the image, I JUST NEED THE PATH!!.
Please Help!
Code so far:
@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(this exception never changes, no matter which approach I use):
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.access$1400(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.access$1400(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)
Upvotes: 0
Views: 762
Reputation: 11
If you are using API 24, then you should use FileProvide, the official website of the introduction: https: //developer.android.com/reference/android/support/v4/content/FileProvider.html You should write like this:
Specify a the contents of the storage area and path in XML, using child elements of the element. For example , The following pathsmann tells FileProvider that you intend to request content URIs for the images / subdirectory of your private file area.
<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>
The third step: file is your path
Uri contentUri = getUriForFile (getContext (), getPackageName () + ".provider", file);
Upvotes: 1
Reputation: 1699
There are some different behaviors possessed by different phones. After a lot of research and trying different possibilities, I came up with a solution which is working on all phones on which I tested it (LG G2, Nexus 5, ZTE, Note 5, Nexus 6, Infinix Note 3 Pro and some others I don't remember). Try this if it works. Take according to your needs. It also includes capturing picture from camera, copy it and getting it's path.
//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
}
}
Upvotes: 0
Reputation: 199805
Apps do not have direct file access to any of the contents of the SD card. Therefore even if you could get a 'path' of some sort, your app would not have the ability to read anything from that location.
The only way to reliably access the contents of these files is through ContentResolver.openInputStream() (or the other open
methods if you need an AssetFileDescriptor
, etc).
You can most definitely copy the file to your own cache directory and then do whatever you want with the image.
Upvotes: 2