android एंड्रॉइड 4.4 पर एंड्रॉइड गैलरी(किटकैट) इरादे के लिए अलग यूआरआई देता है। ACTION_GET_CONTENT




android-intent android-gallery (16)

किटकैट (या नई गैलरी से पहले) से पहले Intent.ACTION_GET_CONTENT ने इस तरह एक यूआरआई वापस कर दिया

सामग्री: // मीडिया / बाहरी / images / मीडिया / 3951।

MediaStore.Images.Media.DATA के लिए ContentResolver और quering का उपयोग करके फ़ाइल यूआरएल वापस कर दिया।

किटकैट में हालांकि गैलरी एक यूआरआई ("आखिरी" के माध्यम से) लौटाती है:

सामग्री: //com.android.providers.media.documents/document/image: 3951

इससे मैं कैसे निपटूं?


उन लोगों के लिए जो अभी भी एंड्रॉइड एसडीके संस्करण 23 और उससे ऊपर के साथ @ पॉल बर्क के कोड का उपयोग कर रहे हैं, यदि आपकी प्रोजेक्ट त्रुटि से कह रही है कि आप EXTERNAL_PERMISSION गुम हैं, और आप सुनिश्चित हैं कि आपने पहले से ही अपने AndroidManifest.xml फ़ाइल में उपयोगकर्ता-अनुमति को जोड़ा है। ऐसा इसलिए है क्योंकि आप एंड्रॉइड एपीआई 23 या उससे ऊपर में हो सकते हैं और Google रनटाइम में फ़ाइल तक पहुंचने के लिए कार्रवाई करते समय फिर से अनुमति की गारंटी के लिए आवश्यक बनाता है।

इसका अर्थ है: यदि आपका एसडीके संस्करण 23 या उससे ऊपर है, तो आप चित्र फ़ाइल का चयन करते समय रीड और लिखने की अनुमति के लिए कहा जाता है और इसके यूआरआई को जानना चाहते हैं।

और पॉल बर्क के समाधान के अलावा, मेरा कोड निम्नलिखित है। मैं इन कोड को जोड़ता हूं और मेरी परियोजना ठीक काम करने लगती है।

private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static final String[] PERMISSINOS_STORAGE = {
    Manifest.permission.READ_EXTERNAL_STORAGE,
    Manifest.permission.WRITE_EXTERNAL_STORAGE
};

public static void verifyStoragePermissions(Activity activity) {
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(
                activity,
                PERMISSINOS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

और आपकी गतिविधि और टुकड़े में जहां आप यूआरआई के लिए पूछ रहे हैं:

private void pickPhotoFromGallery() {

    CompatUtils.verifyStoragePermissions(this);
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    // startActivityForResult(intent, REQUEST_PHOTO_LIBRARY);
    startActivityForResult(Intent.createChooser(intent, "选择照片"),
            REQUEST_PHOTO_LIBRARY);
}

मेरे मामले में, CompatUtils.java वह है जहां मैं सत्यापित स्टोरेजप्रमिशन विधि को परिभाषित करता हूं (स्थिर प्रकार के रूप में, इसलिए मैं इसे अन्य गतिविधि के भीतर कॉल कर सकता हूं)।

इसके अलावा यदि आपको यह देखने के लिए पहले कोई राज्य बनाना है कि मौजूदा एसडीके संस्करण 23 से ऊपर है या नहीं, तो सत्यापित करें कि आप कॉन्फ़िगरेशनप्रदर्शन विधि को कॉल करें।


जैसे ही कॉमन्सवेयर का उल्लेख किया गया है, आपको यह नहीं मानना ​​चाहिए कि सामग्रीResolver के माध्यम से प्राप्त स्ट्रीम फ़ाइल में कनवर्ट करने योग्य है।

आपको वास्तव में क्या करना चाहिए ContentProvider से ContentProvider , फिर इसमें से बिटमैप बनाएं। और यह 4.4 और पुराने संस्करणों पर भी काम करता है, प्रतिबिंब की कोई आवश्यकता नहीं है।

    //cxt -> current context

    InputStream input;
    Bitmap bmp;
    try {
        input = cxt.getContentResolver().openInputStream(fileUri);
        bmp = BitmapFactory.decodeStream(input);
    } catch (FileNotFoundException e1) {

    }

बेशक यदि आप बड़ी छवियों को संभालते हैं, तो आपको उन्हें उचित inSampleSize लोड करना चाहिए: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html । लेकिन यह एक और विषय है।


आपके प्रश्न का उत्तर यह है कि आपको अनुमतियां रखने की आवश्यकता है। अपनी manifest.xml फ़ाइल में निम्न कोड टाइप करें:

<uses-sdk  android:minSdkVersion="8"   android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.WRITE_OWNER_DATA"></uses-permission>
<uses-permission android:name="android.permission.READ_OWNER_DATA"></uses-permission>`

यह मेरे लिए काम किया ...


Please try to avoid using takePersistableUriPermission method because it raised runtime exception for me. /** * Select from gallery. * /

public void selectFromGallery() {
    if (Build.VERSION.SDK_INT < AppConstants.KITKAT_API_VERSION) {

        Intent intent = new Intent(); 
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        ((Activity)mCalledContext).startActivityForResult(intent,AppConstants.GALLERY_INTENT_CALLED);

    } else {

        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        ((Activity)mCalledContext).startActivityForResult(intent, AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED);
    }
}

OnActivity for result to handle the image data:

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    //gallery intent result handling before kit-kat version
    if(requestCode==AppConstants.GALLERY_INTENT_CALLED 
            && resultCode == RESULT_OK) {

        Uri selectedImage = data.getData();
        String[] filePathColumn = {MediaStore.Images.Media.DATA};
        Cursor cursor = getContentResolver().query(selectedImage,filePathColumn, null, null, null);
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String filePath = cursor.getString(columnIndex);
        cursor.close();
        photoFile = new File(filePath);
        mImgCropping.startCropImage(photoFile,AppConstants.REQUEST_IMAGE_CROP);

    }
    //gallery intent result handling after kit-kat version
    else if (requestCode == AppConstants.GALLERY_AFTER_KITKAT_INTENT_CALLED 
            && resultCode == RESULT_OK) {

        Uri selectedImage = data.getData();
        InputStream input = null;
        OutputStream output = null;

        try {
            //converting the input stream into file to crop the 
            //selected image from sd-card.
            input = getApplicationContext().getContentResolver().openInputStream(selectedImage);
            try {
                photoFile = mImgCropping.createImageFile();
            } catch (IOException e) {
                e.printStackTrace();
            }catch(Exception e) {
                e.printStackTrace();
            }
            output = new FileOutputStream(photoFile);

            int read = 0;
            byte[] bytes = new byte[1024];

            while ((read = input.read(bytes)) != -1) {
                try {
                    output.write(bytes, 0, read);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

वही समस्या थी, ऊपर दिए गए समाधान की कोशिश की लेकिन हालांकि यह आम तौर पर काम करता था, किसी कारण से मुझे कुछ छवियों के लिए उरी सामग्री प्रदाता पर अनुमति अस्वीकार कर रही थी, हालांकि मेरे पास android.permission.MANAGE_DOCUMENTS अनुमति ठीक से जोड़ दी गई थी।

वैसे भी अन्य समाधान मिला जो कि किटकैट दस्तावेजों की बजाय छवि गैलरी खोलने के लिए मजबूर करना है:

// KITKAT

i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i, CHOOSE_IMAGE_REQUEST);

और फिर छवि लोड करें:

Uri selectedImageURI = data.getData();
input = c.getContentResolver().openInputStream(selectedImageURI);
                BitmapFactory.decodeStream(input , null, opts);

संपादित करें

ACTION_OPEN_DOCUMENT लिए आपको अनुमति झंडे आदि जारी रखने की आवश्यकता हो सकती है और आम तौर पर अक्सर सुरक्षा अपवादों में परिणाम होता है ...

अन्य समाधान ACTION_GET_CONTENT का उपयोग c.getContentResolver().openInputStream(selectedImageURI) के साथ संयुक्त करना है c.getContentResolver().openInputStream(selectedImageURI) जो प्री-केके और केके दोनों पर काम करेगा। किटकैट नए दस्तावेज़ों का उपयोग तब करेगा और यह समाधान फ़ोटो, गैलरी, फाइल एक्सप्लोरर, ड्रॉपबॉक्स, Google ड्राइव इत्यादि जैसे सभी ऐप्स के साथ काम करेगा ...) लेकिन याद रखें कि इस समाधान का उपयोग करते समय आपको अपने onActivityResult() में छवि बनाना होगा और उदाहरण के लिए इसे एसडी कार्ड पर स्टोर करें। अगली ऐप लॉन्च पर सहेजी गई यूरी से इस छवि को दोबारा शुरू करने से आप सामग्री एपीआई पर सुरक्षा अपवाद फेंक देंगे, भले ही आप Google एपीआई दस्तावेज़ों में वर्णित अनुमति झंडे जोड़ते हैं (यही हुआ जब मैंने कुछ परीक्षण किया)

इसके अतिरिक्त एंड्रॉइड डेवलपर एपीआई दिशानिर्देश सुझाव देते हैं:

ACTION_OPEN_DOCUMENT का उद्देश्य ACTION_GET_CONTENT के प्रतिस्थापन का इरादा नहीं है। आपको जिस ऐप का उपयोग करना चाहिए वह आपके ऐप की ज़रूरतों पर निर्भर करता है:

यदि आप अपने ऐप को डेटा को आसानी से पढ़ने / आयात करने के लिए चाहते हैं तो ACTION_GET_CONTENT का उपयोग करें। इस दृष्टिकोण के साथ, ऐप डेटा की एक प्रति आयात करता है, जैसे छवि फ़ाइल।

यदि आप अपने ऐप को दीर्घकालिक, दस्तावेज़ प्रदाता के स्वामित्व वाले दस्तावेज़ों तक निरंतर पहुंच चाहते हैं, तो ACTION_OPEN_DOCUMENT का उपयोग करें। एक उदाहरण एक फोटो संपादन एप होगा जो उपयोगकर्ताओं को दस्तावेज़ प्रदाता में संग्रहीत छवियों को संपादित करने देता है।


@paul burke's answer works fine for both camera and gallery pictures for API level 19 and above, but it doesn't work if your Android project's minimum SDK is set to below 19, and some answers referring above doesn't work for both gallery and camera. Well, I have modified @paul burke's code which works for API level below 19. Below is the code.

public static String getPath(final Context context, final Uri uri) {

    final boolean isKitKat = Build.VERSION.SDK_INT >=
                             Build.VERSION_CODES.KITKAT;
    Log.i("URI",uri+"");
    String result = uri+"";

    // DocumentProvider
    // if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
    if (isKitKat && (result.contains("media.documents"))) {

        String[] ary = result.split("/");
        int length = ary.length;
        String imgary = ary[length-1];
        final String[] dat = imgary.split("%3A");

        final String docId = dat[1];
        final String type = dat[0];

        Uri contentUri = null;
        if ("image".equals(type)) {
            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        }
        else if ("video".equals(type)) {
        }
        else if ("audio".equals(type)) {
        }

        final String selection = "_id=?";
        final String[] selectionArgs = new String[] {
            dat[1]
        };

        return getDataColumn(context, contentUri, selection, selectionArgs);
    }
    else
    if ("content".equalsIgnoreCase(uri.getScheme())) {
        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    }

    return null;
}

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;
}

I've tried several of the answers here, and I think I have a solution that will work every time and manages permissions as well.

It is based on the clever solution from LEO. This post should contain all the code you need to make this work, and it should work on any phone and Android version ;)

In order to have the ability to pick a file from an SD card, you'll need this in your manifest:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Constants:

private static final int PICK_IMAGE = 456; // Whatever number you like
public static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL = 28528; // Whatever number you like
public static final String FILE_TEMP_NAME = "temp_image"; // Whatever file name you like

Check permission and launchImagePick if possible

if (ContextCompat.checkSelfPermission(getThis(),
        Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {

    ActivityCompat.requestPermissions(getThis(),
            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
            MY_PERMISSIONS_REQUEST_READ_EXTERNAL);
}
else {
    launchImagePick();
}

Permission response

@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull
                                         String permissions[],
                                       @NonNull
                                         int[] grantResults) {

    if (manageReadExternalPermissionResponse(this, requestCode, grantResults)) {
        launchImagePick();
    }
}

Manage permission response

public static boolean manageReadExternalPermissionResponse(final Activity activity, int requestCode, int[] grantResults) {

    if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL) {

        // If request is cancelled, the result arrays are empty.

        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

            // Permission was granted, yay! Do the
            // contacts-related task you need to do.
            return true;

        } else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {

            boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity,
                    Manifest.permission.READ_EXTERNAL_STORAGE);

            if (!showRationale) {
                // The user also CHECKED "never ask again".
                // You can either enable some fall back,
                // disable features of your app
                // or open another dialog explaining
                // again the permission and directing to
                // the app setting.

            } else {
                // The user did NOT check "never ask again".
                // This is a good place to explain the user
                // why you need the permission and ask if he/she wants
                // to accept it (the rationale).
            }
        } else {
            // Permission denied, boo! Disable the
            // functionality that depends on this permission.
        }
    }
    return false;
}

Launch image pick

private void launchImagePick() {

    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    startActivityForResult(intent, PICK_IMAGE);

    // see onActivityResult
}

Manage Image pick response

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_IMAGE) {

        if (resultCode == Activity.RESULT_OK) {
            if (data != null && data.getData() != null) {

                try {
                     InputStream inputStream = getContentResolver().openInputStream(data.getData())
                     if (inputStream != null) {

                        // No special persmission needed to store the file like that
                        FileOutputStream fos = openFileOutput(FILE_TEMP_NAME, Context.MODE_PRIVATE);

                        final int BUFFER_SIZE = 1 << 10 << 3; // 8 KiB buffer
                        byte[] buffer = new byte[BUFFER_SIZE];
                        int bytesRead = -1;
                        while ((bytesRead = inputStream.read(buffer)) > -1) {
                            fos.write(buffer, 0, bytesRead);
                        }
                        inputStream.close();
                        fos.close();

                        File tempImageFile = new File(getFilesDir()+"/"+FILE_TEMP_NAME);

                        // Do whatever you want with the File

                        // Delete when not needed anymore
                        deleteFile(FILE_TEMP_NAME);
                    }
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                // Error display
            }
        } else {
            // The user did not select any image
        }
    }
}

That's all folks; this works for me on all the telephones I have.


इसे इस्तेमाल करे:

if (Build.VERSION.SDK_INT <19){
    Intent intent = new Intent(); 
    intent.setType("image/jpeg");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(Intent.createChooser(intent, getResources().getString(R.string.select_picture)),GALLERY_INTENT_CALLED);
} else {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("image/jpeg");
    startActivityForResult(intent, GALLERY_KITKAT_INTENT_CALLED);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode != Activity.RESULT_OK) return;
    if (null == data) return;
    Uri originalUri = null;
    if (requestCode == GALLERY_INTENT_CALLED) {
        originalUri = data.getData();
    } else if (requestCode == GALLERY_KITKAT_INTENT_CALLED) {
        originalUri = data.getData();
        final int takeFlags = data.getFlags()
                & (Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // Check for the freshest data.
        getContentResolver().takePersistableUriPermission(originalUri, takeFlags);
    }

    loadSomeStreamAsynkTask(originalUri);

}

शायद जरूरत है

@SuppressLint ( "NewApi")

के लिये

takePersistableUriPermission


बस कहना चाहता था कि यह जवाब शानदार है और मैं बिना किसी समस्या के लंबे समय तक इसका उपयोग कर रहा हूं। लेकिन कुछ समय पहले मैंने एक समस्या पर ठोकर खाई है कि content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf प्रारूप content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf में यूआरआई लौटाता content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdf और इसलिए ऐप को NumberFormatException साथ दुर्घटनाग्रस्त कर दिया गया है क्योंकि लंबे समय तक अपने यूरी सेगमेंट को पार्स करना असंभव है। लेकिन raw: सेगमेंट में सीधी यूरी होती है जिसे संदर्भित फ़ाइल को पुनः प्राप्त करने के लिए उपयोग किया जा सकता है। तो मैंने इसे डाउनलोड करने के साथ isDownloadsDocument(uri) को बदलकर इसे ठीक कर दिया है:

final String id = DocumentsContract.getDocumentId(uri);
if (!TextUtils.isEmpty(id)) {
if (id.startsWith("raw:")) {
    return id.replaceFirst("raw:", "");
}
try {
    final Uri contentUri = ContentUris.withAppendedId(
            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
    return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
    Timber.e(e, "Downloads provider returned unexpected uri %s, quitting", uri.toString());
    return null;
}
}

This worked fine for me:

else if(requestCode == GALLERY_ACTIVITY_NEW && resultCode == Activity.RESULT_OK)
{
    Uri uri = data.getData();
    Log.i(TAG, "old uri =  " + uri);
    dumpImageMetaData(uri);

    try {
        ParcelFileDescriptor parcelFileDescriptor =
                getContentResolver().openFileDescriptor(uri, "r");
        FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
        Log.i(TAG, "File descriptor " + fileDescriptor.toString());

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);

        options.inSampleSize =
           BitmapHelper.calculateInSampleSize(options,
                                              User.PICTURE_MAX_WIDTH_IN_PIXELS,
                                              User.PICTURE_MAX_HEIGHT_IN_PIXELS);
        options.inJustDecodeBounds = false;

        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
        imageViewPic.setImageBitmap(bitmap);

        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
        // get byte array here
        byte[] picData = stream.toByteArray();
        ParseFile picFile = new ParseFile(picData);
        user.setProfilePicture(picFile);
    }
    catch(FileNotFoundException exc)
    {
        Log.i(TAG, "File not found: " + exc.toString());
    }
}

इसके लिए कोई विशेष अनुमति की आवश्यकता नहीं है, और स्टोरेज एक्सेस फ्रेमवर्क के साथ-साथ अनौपचारिक ContentProvider पैटर्न ( ContentProvider फ़ील्ड में फ़ाइल पथ) के साथ काम करता है।

/**
 * 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 the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        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 index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(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());
}

/**
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}

here इस विधि का एक अद्यतित संस्करण देखें।


मैं यह करता हूं:

Uri selectedImageURI = data.getData();    imageFile = new File(getRealPathFromURI(selectedImageURI)); 

private String getRealPathFromURI(Uri contentURI) {
  Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
  if (cursor == null) { // Source is Dropbox or other similar local file path
      return contentURI.getPath();
      } else { 
      cursor.moveToFirst(); 
      int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); 
      return cursor.getString(idx); 
  }
}

नोट: managedQuery() विधि बहिष्कृत है, इसलिए मैं इसका उपयोग नहीं कर रहा हूं।

यह उत्तर प्रश्न पर m3n0R से है एंड्रॉइड Uri.getPath () द्वारा वास्तविक पथ प्राप्त करता है और मैं कोई क्रेडिट दावा नहीं करता हूं। मैंने सोचा कि जिन लोगों ने इस मुद्दे को हल नहीं किया है, वे अभी भी इसका इस्तेमाल कर सकते हैं।


मेरा मानना ​​है कि पहले से पोस्ट किए गए प्रतिक्रियाओं को लोगों को सही दिशा में जाना चाहिए। हालांकि यहां मैंने जो किया वह विरासत कोड जिसे मैं अद्यतन कर रहा था, के लिए समझ में आया। विरासत कोड बदलने के लिए गैलरी से यूआरआई का उपयोग कर रहा था और फिर छवियों को बचा सकता था।

4.4 (और Google ड्राइव) से पहले, यूआरआई इस तरह दिखेगा: सामग्री: // मीडिया / बाहरी / छवियों / मीडिया / 41

जैसा कि सवाल में बताया गया है, वे अक्सर इस तरह दिखते हैं: सामग्री: //com.android.providers.media.documents/document/image: 3951

चूंकि मुझे छवियों को सहेजने और पहले से मौजूद कोड को परेशान करने की क्षमता की आवश्यकता नहीं है, इसलिए मैंने गैलरी से ऐप के डेटा फ़ोल्डर में यूआरआई की प्रतिलिपि बनाई है। फिर डेटा फ़ोल्डर में सहेजी गई छवि फ़ाइल से एक नया यूआरआई उत्पन्न हुआ।

यहां विचार है:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent), CHOOSE_IMAGE_REQUEST);

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);

    File tempFile = new File(this.getFilesDir().getAbsolutePath(), "temp_image");

    //Copy URI contents into temporary file.
    try {
        tempFile.createNewFile();
        copyAndClose(this.getContentResolver().openInputStream(data.getData()),new FileOutputStream(tempFile));
    }
    catch (IOException e) {
        //Log Error
    }

    //Now fetch the new URI
    Uri newUri = Uri.fromFile(tempFile);

    /* Use new URI object just like you used to */
 }

नोट - copyAndClose () फ़ाइल आउटपुट को एक FileOutputStream में कॉपी करने के लिए फ़ाइल I / O करता है। कोड पोस्ट नहीं किया गया है।


Building up on Paul Burke's answer I faced many problems resolving external SD card's URI path as most of the suggested "built-in" functions return paths which do not get resolved to files.

However, this is my approach of his // TODO handle non-primary volumes .

String resolvedPath = "";
File[] possibleExtSdComposites = context.getExternalFilesDirs(null);
for (File f : possibleExtSdComposites) {
    // Reset final path
    resolvedPath = "";

    // Construct list of folders
    ArrayList<String> extSdSplit = new ArrayList<>(Arrays.asList(f.getPath().split("/")));

    // Look for folder "<your_application_id>"
    int idx = extSdSplit.indexOf(BuildConfig.APPLICATION_ID);

    // ASSUMPTION: Expected to be found at depth 2 (in this case ExtSdCard's root is /storage/0000-0000/) - e.g. /storage/0000-0000/Android/data/<your_application_id>/files
    ArrayList<String> hierarchyList = new ArrayList<>(extSdSplit.subList(0, idx - 2));

    // Construct list containing full possible path to the file
    hierarchyList.add(tail);
    String possibleFilePath = TextUtils.join("/", hierarchyList);

    // If file is found --> success
    if (idx != -1 && new File(possibleFilePath).exists()) {
        resolvedPath = possibleFilePath;
        break;
    }
}

if (!resolvedPath.equals("")) {
    return resolvedPath;
} else {
    return null;
}

Note it depends on hierarchy which might be different on every phone manufacturer - I have not tested them all (it worked well so far on Xperia Z3 API 23 and Samsung Galaxy A3 API 23).

Please confirm if it does not perform well elsewhere.


मैंने कई उत्तरों को एक कार्य समाधान में जोड़ दिया है जो फ़ाइल पथ के साथ परिणाम देता है

उदाहरण उद्देश्य के लिए माइम प्रकार अप्रासंगिक है।

            Intent intent;
            if(Build.VERSION.SDK_INT >= 19){
                intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
                intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
            }else{
                intent = new Intent(Intent.ACTION_GET_CONTENT);
            }
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setType("application/octet-stream");
            if(isAdded()){
                startActivityForResult(intent, RESULT_CODE);
            }

परिणाम संभाल

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if( requestCode == RESULT_CODE && resultCode == Activity.RESULT_OK) {
        Uri uri = data.getData();
        if (uri != null && !uri.toString().isEmpty()) {
            if(Build.VERSION.SDK_INT >= 19){
                final int takeFlags = data.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
                //noinspection ResourceType
                getActivity().getContentResolver()
                        .takePersistableUriPermission(uri, takeFlags);
            }
            String filePath = FilePickUtils.getSmartFilePath(getActivity(), uri);
            // do what you need with it...
        }
    }
}

FilePickUtils

import android.annotation.SuppressLint;
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;

public class FilePickUtils {
    private static String getPathDeprecated(Context ctx, Uri uri) {
        if( uri == null ) {
            return null;
        }
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = ctx.getContentResolver().query(uri, projection, null, null, null);
        if( cursor != null ){
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        return uri.getPath();
    }

    public static String getSmartFilePath(Context ctx, Uri uri){

        if (Build.VERSION.SDK_INT < 19) {
            return getPathDeprecated(ctx, uri);
        }
        return  FilePickUtils.getPath(ctx, uri);
    }

    @SuppressLint("NewApi")
    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());
    }

}

If anyone's interested, I made a working Kotlin version for ACTION_GET_CONTENT :

var path: String = uri.path // uri = any content Uri
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (path.contains("/document/image:")) { // files selected from "Documents"
    databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
    selection = "_id=?"
    selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
    databaseUri = uri
    selection = null
    selectionArgs = null
}
try {
    val projection = arrayOf(MediaStore.Images.Media.DATA,
        MediaStore.Images.Media._ID,
        MediaStore.Images.Media.ORIENTATION,
        MediaStore.Images.Media.DATE_TAKEN) // some example data you can query
    val cursor = context.contentResolver.query(databaseUri,
        projection, selection, selectionArgs, null)
    if (cursor.moveToFirst()) {
        // do whatever you like with the data
    }
    cursor.close()
} catch (e: Exception) {
    Log.e(TAG, e.message, e)
}






android-contentresolver