简体   繁体   中英

Get path to image chosen from gallery(on SD card)

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) 

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.

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:

  1. 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> 
  2. The third step: file is your path

     Uri contentUri = getUriForFile (getContext (), getPackageName () + ".provider", file); 

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

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM