অ্যান্ড্রয়েড 4.4 এ অ্যান্ড্রয়েড গ্যালারী (কিটকাট) ইনটেন্টের জন্য বিভিন্ন ইউআরআই ফেরত দেয় CTION


214

কিটকাটের (বা নতুন গ্যালারী হওয়ার আগে) আগে এইভাবে Intent.ACTION_GET_CONTENTকোনও ইউআরআই ফেরত

বিষয়বস্তু: // মিডিয়া / বহিরাগত / ছবি / মিডিয়া / 3951।

ফাইলটির ইউআরএল ফিরিয়ে দেওয়া ContentResolverএবং এর জন্য কোয়েরিং ব্যবহার করে MediaStore.Images.Media.DATA

কিটকাটে অবশ্য গ্যালারীটি ইউআরআই দেয় ("শেষ" মাধ্যমে):

বিষয়বস্তু: //com.android.providers.media.documents/document/image: 3951

আমি কীভাবে এটি পরিচালনা করব?


21
কাফের বাইরে, আমি সেই সামগ্রীটি ব্যবহারের এমন উপায়গুলি খুঁজতে পারি যাতে ফাইলটিতে সরাসরি অ্যাক্সেসের প্রয়োজন হয় না। উদাহরণস্বরূপ, এটি Uriস্ট্রিম হিসাবে খোলারযোগ্য হওয়া উচিত ContentResolver। আমি দীর্ঘদিন ধরে এমন অ্যাপ্লিকেশনগুলি নিয়ে ঘাবড়ে এসেছি যা ধরে নিয়েছে যে content:// Uriকোনও ফাইলকে প্রতিনিধিত্ব করে এমনটি সর্বদা একটিতে রূপান্তরিত হতে পারে File
কমন্সওয়্যার

1
@ কমন্সওয়্যার, যদি আমি স্ক্লাইট ডিবিতে কোনও চিত্রের পথটি সংরক্ষণ করতে চাই যাতে আমি এটি পরে খুলতে পারি, আমি কি ইউআরআই বা পরম ফাইলের পথটি সংরক্ষণ করব?
সাপ

2
@ কমন্সওয়্যার আমি আপনার নার্ভাসনে একমত :-) তবে, ফাইলের নামটি (একটি চিত্রের জন্য) নেটিভ কোডে পাস করতে আমার সক্ষম হওয়া দরকার। একটি সমাধান একটি ব্যবহার করে তথ্য প্রাপ্ত কপি হয় InputStreamউপর ContentResolverতাই এটি একটি পরিচিত ফাইলের নাম রয়েছে একটি প্রি-মনোনীত হন। তবে এটি আমার কাছে অপব্যয়জনক মনে হচ্ছে sounds অন্য কোন পরামর্শ?
দারেনপ

2
@দারেনপ: উম্মম ..., ওভার জেএনআই নিয়ে কাজ করার জন্য নেটিভ কোডটি আবার লিখবেন InputStream? দুর্ভাগ্যক্রমে, আপনার জন্য অনেকগুলি বিকল্প নেই।
কমন্সওয়েয়ার

1
এটি জানতে দরকারী। আপনার প্রতিক্রিয়ার জন্য ধন্যবাদ. আমি তখন থেকেই জানতে পেরেছি যে আমরা এখন কোনও ফাইলের পরিবর্তে চিত্রটি সি ++ এ মেমোরিতে প্রেরণ করছি যাতে এটি এখন আমরা InputStreamকোনও ফাইলের পরিবর্তে (যা দুর্দান্ত) ব্যবহার করতে পারি । কেবল এক্সআইএফ ট্যাগের পড়া সামান্য কৌশলযুক্ত এবং এর জন্য ড্র নোকসের লাইব্রেরি প্রয়োজন । আপনার মন্তব্যের জন্য অনেক ধন্যবাদ।
darrenp

উত্তর:


108

এটা চেষ্টা কর:

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


1
কিটকাট কোডটি কী করছে তা বিশদ দেওয়ার জন্য আপনি কি আপত্তি করবেন? এর জন্য কি নতুন কোনও অনুমতি প্রয়োজন? প্রাক KitKat কোড আমার জন্য KitKat এও কাজ করে। তাহলে কেন আমি কিটক্যাট-এর জন্য আলাদা কোড ব্যবহার করব? ধন্যবাদ।
মাইকেল গ্রেফেন্ডার

67
দেখে মনে হচ্ছে আমরা নতুন এসডিএসএস ইউরি থেকে পথ পাচ্ছি না। গুগল যথাযথ দলিলপত্র ও ঘোষণা ছাড়াই এই ধরণের পরিবর্তন করেছে এটি লজ্জার বিষয়।
ব্যবহারকারী 65721

1
আপনি কীভাবে ফাইলের ইউআরএল পাবেন তা ব্যাখ্যা করতে পারেন? আমি এসডিকার্ডে আসল পথটি পেতে চাই। উদাহরণস্বরূপ, যদি এটি কোনও চিত্র হয় তবে আমি এই পথটি / স্টোরেজ / এসডিকার্ড0/ডিসিআইএম / ক্যামেরা / আইএমজি_20131118_153817_119.jpg নথিটি উরির পরিবর্তে পেতে চাই।
vlvaro

4
KitKat ডক্সের উপর ভিত্তি করে ( বিকাশকারী.অ্যান্ড্রয়েড .com/about/versions/…) অপেরা অন্য অ্যাপ্লিকেশন (গুলি) এর মালিকানাধীন দস্তাবেজগুলি ব্যবহার / সম্পাদনা করার ইচ্ছা না করে অপরিহার্যভাবে এটির প্রয়োজন হতে পারে। ওপি যদি কোনও অনুলিপি চায় বা পুরানো সংস্করণগুলির সাথে সামঞ্জস্যপূর্ণ উপায়ে জিনিসগুলি করতে চায় তবে @ ভয়েটেজের উত্তর আরও উপযুক্ত হবে।
কলিন এম

8
এটি আমার পক্ষে কাজ করছে না। আমি নিম্নলিখিত ব্যতিক্রমটি পেয়েছি (4..৪.২ স্টকটিতে): ই / অ্যান্ড্রয়েডআরটাইম (২৯২০৪): জাভা.এলং.সিকিউরিটি এক্সেকশন দ্বারা অনুরোধ করা হয়েছে: অনুরোধ করা পতাকাগুলি 0x1, তবে কেবল 0x0 এর অনুমতি রয়েছে
রাসেল স্টুয়ার্ট

177

এর জন্য কোনও বিশেষ অনুমতি প্রয়োজন নেই, এবং স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্কের পাশাপাশি বেসরকারী ContentProviderপ্যাটার্ন ( _dataক্ষেত্রের ফাইলের পথ ) নিয়ে কাজ করে।

/**
 * 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());
}

এই পদ্ধতির একটি আধুনিক সংস্করণ এখানে দেখুন


2
এটি স্ট্যান্ডার্ড গ্যালারী অ্যাপ্লিকেশনগুলি ব্যবহার করে একটি 4.4 নেক্সাস 5 নথি ইউআই এবং কিছু অন্যান্য প্রিফ কিটক্যাট ডিভাইসে দুর্দান্তভাবে কাজ করেছে, পলকে ধন্যবাদ!
জোশ

1
এর জন্য ধন্যবাদ, এসডিকে 19 দিয়ে আমার এটিকে পেতে যুগে যুগে সময় লেগেছে! আমার সমস্যাটি হ'ল আমার ডিভাইস ফাইল ব্রাউজার হিসাবে গুগল ড্রাইভ ব্যবহার করছে। ফাইলটি যদি ডিভাইসে থাকে তবে চিত্রের পথটি ভাল হয়ে যায় তবে যদি ফাইলটি ড্রাইভে থাকে তবে এটি খুলবে না। হয়তো আমার কেবল গুগল ড্রাইভ থেকে চিত্র খোলার বিষয়টি নিয়ে নজর দেওয়া দরকার। জিনিসটি হ'ল আমার অ্যাপটি ফাইলের পাথ ব্যবহার করার জন্য এবং ইনস্যাম্পলিং ব্যবহার করে চিত্র পাওয়ার জন্য লেখা হয়েছে ...
রুআওয়ার

2
@ রুয়াওয়্যার আপনি যখন কোনও ড্রাইভ ফাইল নির্বাচন করেন, এটি আবার দেয় Authority: com.google.android.apps.docs.storageএবং দেয় Segments: [document, acc=1;doc=667]। আমি নিশ্চিত নই, তবে ধরে নিই যে docমানটি সেই Uriআইডি যার বিরুদ্ধে আপনি জিজ্ঞাসা করতে পারেন। আপনার সম্ভবত এখানে "অ্যান্ড্রয়েডে আপনার অ্যাপ্লিকেশনটিকে অনুমোদন দিন": বিস্তারিত হিসাবে সেট আপ করার জন্য অনুমতিগুলির প্রয়োজন হবে: বিকাশকারীরা . com/drive/integrate-android-ui । যদি আপনি এটি বের করে থাকেন তবে দয়া করে এখানে আপডেট করুন।
পল বার্ক

30
এটা একেবারে ভয়াবহ! আপনার "চিট" এই জাতীয় কোড প্রচার করা চালিয়ে যাওয়া উচিত নয়। এটি কেবলমাত্র সেই উত্স অ্যাপ্লিকেশনগুলিকে সমর্থন করে যার জন্য আপনি প্যাটার্নটি জানেন এবং ডকুমেন্ট সরবরাহকারী মডেলের পুরো পয়েন্টটি স্বেচ্ছাসেবী উত্সগুলিকে সমর্থন করে
j__m

2
_dataকাজ করতে না চায় যখন ContentProvider এটা সমর্থন করে না। @ কমন্সওয়্যার নির্দেশাবলী অনুসরণ এবং পুরো ফাইল পাথ আর ব্যবহার না করার পরামর্শ দেওয়া হচ্ছে , কারণ এটি আসল ফাইলের পরিবর্তে ড্রপবক্স ক্লাউডের কোনও ফাইল হতে পারে।
সোশিয়াল

67

একই সমস্যা ছিল, উপরের সমাধানটি চেষ্টা করে দেখুন তবে এটি সাধারণভাবে কাজ করেছে, কিছু কারণে আমি কিছু চিত্রের জন্য উরি সামগ্রী সরবরাহকারীর অনুমতি অস্বীকার পাচ্ছিলাম যদিও আমার 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)যা প্রি-কে এবং কেকে উভয় ক্ষেত্রেই কাজ করবে। কিটক্যাট তখন নতুন দস্তাবেজ দর্শন ব্যবহার করবে এবং এই সমাধানটি ফটো, গ্যালারী, ফাইল এক্সপ্লোরার, ড্রপবক্স, গুগল ড্রাইভ ইত্যাদির মতো সমস্ত অ্যাপ্লিকেশনের সাথে কাজ করবে ... তবে মনে রাখবেন যে এই সমাধানটি ব্যবহার করার সময় আপনার নিজের মধ্যে চিত্র তৈরি করতে onActivityResult()হবে এবং এটি সংরক্ষণ করতে হবে উদাহরণস্বরূপ এসডি কার্ড। পরবর্তী অ্যাপ্লিকেশন প্রবর্তনের সময় সংরক্ষিত ইউরি থেকে এই চিত্রটি পুনরুদ্ধার করা গুগল এপিআই ডক্সে বর্ণিত অনুমতির পতাকাগুলি যুক্ত করার পরেও বিষয়বস্তু সমাধানের ক্ষেত্রে সুরক্ষা ব্যতিক্রম ছুঁড়ে ফেলা হবে (যখন আমি কিছু পরীক্ষা করেছি তখনই এটি ঘটেছে)

অতিরিক্তভাবে অ্যান্ড্রয়েড বিকাশকারী এপিআই গাইডলাইনগুলি পরামর্শ দেয়:

ACTION_OPEN_DOCUMENT ACTION_GET_CONTENT এর প্রতিস্থাপনের উদ্দেশ্যে নয়। আপনার যেটি ব্যবহার করা উচিত তা আপনার অ্যাপের প্রয়োজনের উপর নির্ভর করে:

আপনি যদি নিজের অ্যাপটি সহজেই ডেটা পড়তে / আমদানি করতে চান তবে ACTION_GET_CONTENT ব্যবহার করুন। এই পদ্ধতির সাথে অ্যাপ্লিকেশন কোনও চিত্র ফাইলের মতো ডেটার একটি অনুলিপি আমদানি করে।

আপনি যদি অ্যাপ্লিকেশনটিতে দীর্ঘকালীন, দস্তাবেজ সরবরাহকারীর মালিকানাধীন দস্তাবেজগুলিতে অবিচ্ছিন্ন অ্যাক্সেস চান তবে ACTION_OPEN_DOCUMENT ব্যবহার করুন। উদাহরণ হ'ল একটি ফটো-সম্পাদনা অ্যাপ্লিকেশন যা ব্যবহারকারীদের একটি দস্তাবেজ সরবরাহকারীর মধ্যে থাকা চিত্রগুলি সম্পাদনা করতে দেয়।


1
এই উত্তরটিতে আমার উদ্দেশ্যগুলির জন্য সঠিক তথ্য রয়েছে। শর্তসাপেক্ষে KitKat এ ACTION_PICK এবং EXTERNAL_CONTENT_URI ব্যবহার করে কন্ট্রোলসোলভারের মাধ্যমে গ্যালারীটিতে চিত্রগুলি সম্পর্কে মেটা-ডেটা পাওয়ার একই ক্ষমতাটি কেবল ACTION_GET_CONTENT ব্যবহার করে পুরানো সংস্করণগুলিতে সম্ভব provided
কলিন এম

@ ভয়েটেজ, এই ইউআরআই কি আপনার বার্তার মাধ্যমে চিত্রের পুরো আসল পথে রূপান্তর করতে পারে?
সাপ

আমি বিশ্বাস করি, এটি কিটকাটের ঠিক আগের মতোই কাজ করা উচিত কারণ এই কোডটি কে কে ডকুমেন্টস ভিউয়ের পরিবর্তে চিত্র গ্যালারী খোলার জন্য বাধ্য করে। তবে আপনি যদি চিত্রটি তৈরি করতে এটি ব্যবহার করতে চান তবে এই সমাধানটি আরও ভাল কারণ আসল পথে রূপান্তর করা একটি অতিরিক্ত অযৌক্তিক পদক্ষেপ।
ভয়েটেজ

4
পরিবর্তে আমার জন্যও কাজ করেছেন Intent.ACTION_GET_CONTENT। যাইহোক আমি ব্যবহারকারীকে ব্রাউজ করার জন্য অ্যাপ্লিকেশনটি চয়ন করতে, এবং প্রত্যাশা অনুযায়ী কাজ করতে, Intent.createChooser()নতুনটিতে মোড়ক রেখেছি Intent। এই সমাধানের জন্য কেউ কি ত্রুটিগুলি দেখতে পাবে?
lorenzo-s

1
এমন যে কেউ উদ্ধৃতি ভাবছি এর জন্য থেকে আসে developer.android.com/guide/topics/providers/...
snark

38

কমন্সওয়্যার যেমন উল্লেখ করেছেন, আপনার ধরে নেওয়া উচিত নয় যে আপনি যে স্ট্রিমটি পেয়েছেন ContentResolverসেটি ফাইলের মধ্যে রূপান্তরযোগ্য।

আপনি কি সত্যিই কি করা উচিত খুলতে হয় InputStreamথেকে 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 । তবে এটি অন্য বিষয়।


এটি নেক্সাস 4 চলমান কিটক্যাট নিয়ে আমার পক্ষে কাজ করছে না তবে এটি গ্যালাক্সি এস 3 দিয়ে চলছে 4.1.2
ড্যান 2552

@ Dan2552 কোন অংশটি কাজ করছে না? আপনি কোন ব্যতিক্রম পেতে?
মিচা কে

দেখা গেল আমি গ্যালারীটিতে ভুল উদ্দেশ্য কলটি ব্যবহার করছিলাম। আমি এমন একটি ব্যবহার করছিলাম যা কোনও ধরণের নথির জন্য ছিল তবে ফাইল এক্সটেনশন ফিল্টার সহ।
ড্যান 2552

2
কী সুন্দর উত্তর, ধন্যবাদ! অন্যদের জন্য এই উত্তরটি অনুসরণ করে 'সিএসটি' বর্তমান প্রসঙ্গে বোঝায় এবং সাধারণত 'এটি' হবে।
thomasforth

1
এর অর্থ সম্ভবত ফাইলটি নেই। ইউআরআই ঠিক আছে বলে মনে হচ্ছে।
Michał K

33

আমি বিশ্বাস করি ইতিমধ্যে পোস্ট করা প্রতিক্রিয়াগুলি লোকদের সঠিক দিকে যেতে হবে। যাইহোক, আমি হালনাগাদ কোডটি আপডেট করছিলাম সেটির জন্য আমি তা বুঝি। লিগ্যাসি কোডটি গ্যালারী থেকে ইউআরআই ব্যবহার করে চিত্রগুলি পরিবর্তন করতে এবং তারপরে সংরক্ষণ করতে পারে।

৪.৪ (এবং গুগল ড্রাইভ) এর আগে ইউআরআইগুলি দেখতে এরকম হবে: সামগ্রী: // মিডিয়া / বাহ্যিক / চিত্র / মিডিয়া / 41

প্রশ্নে বর্ণিত হিসাবে, তারা প্রায়শই এই জাতীয় চেহারা: সামগ্রী: //com.android.providers.media.documents/docament/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 () ইনপুটস্ট্রিমটিকে একটি ফাইলআউটপুট স্ট্রিমে অনুলিপি করতে কেবল ফাইল I / O করে। কোড পোস্ট করা হয় না।


বেশ চালাক আমারও আসল ফাইলটি ইউরি দরকার
বৃহত্তর

তুমি আমার নায়ক, এটাই আমার দরকার ছিল! গুগল ড্রাইভ ফাইলগুলির জন্য দুর্দান্ত কাজ করে
মিশকিন

বাক্স থেকে চিন্তা করুন, তাই না? : ডি এই কোডটি ঠিক তেমনভাবে কাজ করে যা আমি প্রত্যাশা করেছিলাম।
WeirdElfB0y

2
কপিঅ্যান্ডক্লোজের জন্য কোড পোস্ট করুন, উত্তরটি সম্পূর্ণ নয়
বারটেক প্যাকিয়া

24

কেবল এটিই বলতে চেয়েছিলেন যে এই উত্তরটি উজ্জ্বল এবং আমি এটি দীর্ঘকাল ধরে সমস্যা ছাড়াই ব্যবহার করছি। তবে কিছু সময় আগে আমি এমন একটি সমস্যায় পড়ে গিয়েছি যে ডাউনলোডসপ্রোভাইডার ইউআরআইগুলিকে ফর্ম্যাটে ফেরত দেয় content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Fdoc.pdfএবং তাই অ্যাপটি ক্র্যাশ হয়ে যায় NumberFormatExceptionকারণ এর ইউরি বিভাগগুলি দীর্ঘকাল পার্স করা অসম্ভব। তবে raw:বিভাগটিতে সরাসরি ইউরি রয়েছে যা রেফারেন্সযুক্ত ফাইলটি পুনরুদ্ধার করতে ব্যবহার করা যেতে পারে। সুতরাং আমি isDownloadsDocument(uri) ifনিম্নলিখিতটি দিয়ে বিষয়বস্তু প্রতিস্থাপন করে এটি স্থির করেছি :

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) {
    Log.e("FileUtils", "Downloads provider returned unexpected uri " + uri.toString(), e);
    return null;
}
}

2
নিখুঁত কাজ করে! আপনাকে ধন্যবাদ
মাইকিমেকে 396

8

আমি একাধিক উত্তরকে একটি কার্যক্ষম সমাধানের সাথে একত্রিত করেছি যা ফলাফল ফাইলের পথে

মাইম টাইপ উদাহরণ উদ্দেশ্যে অপ্রাসঙ্গিক।

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

}

আমি ইস্যুতে ছিলাম .... uri.getPath () বাহ্যিক / বহিরাগত নিয়ে uri ফিরছিল এবং এটি আর ফিরে আসেনি। যদি ("সামগ্রী" .EqualsIgnoreCase (uri.getScheme ()) ব্লক হয়ে থাকে এবং এটি এখন ভাল কাজ করে তবে এটি কী করে তা আপনি ব্যাখ্যা করতে পারেন
ফয়সালআহ্মেদ

ফাইলপথটি শূন্য হয়ে যাচ্ছে .. ইউরিতে: সামগ্রী: //com.android.externst સંગ્રહ.documents/docament/799B
ভাवेश মোরাদিয়া

7

প্রশ্ন

কোনও ইউআরআই থেকে কীভাবে প্রকৃত ফাইল পাথ পাবেন

উত্তর

আমার জানা মতে, আমাদের ইউআরআই থেকে ফাইলের পাথের দরকার নেই কারণ বেশিরভাগ ক্ষেত্রে আমরা সরাসরি আমাদের কাজ শেষ করতে ইউআরআই ব্যবহার করতে পারি (যেমন ১. বিটম্যাপ করা ২. সার্ভারে একটি ফাইল পাঠানো ইত্যাদি) ।)

1. সার্ভারে প্রেরণ

আমরা কেবলমাত্র ইউআরআই ব্যবহার করে সরাসরি ফাইলটি সার্ভারে প্রেরণ করতে পারি।

ইউআরআই ব্যবহার করে আমরা ইনপুট স্ট্রিম পেতে পারি, যা আমরা সরাসরি মাল্টিপার্টেন্টিটি ব্যবহার করে সার্ভারে প্রেরণ করতে পারি।

উদাহরণ

/**
 * Used to form Multi Entity for a URI (URI pointing to some file, which we got from other application).
 *
 * @param uri     URI.
 * @param context Context.
 * @return Multi Part Entity.
 */
public MultipartEntity formMultiPartEntityForUri(final Uri uri, final Context context) {
    MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, Charset.forName("UTF-8"));
    try {
        InputStream inputStream = mContext.getContentResolver().openInputStream(uri);
        if (inputStream != null) {
            ContentBody contentBody = new InputStreamBody(inputStream, getFileNameFromUri(uri, context));
            multipartEntity.addPart("[YOUR_KEY]", contentBody);
        }
    }
    catch (Exception exp) {
        Log.e("TAG", exp.getMessage());
    }
    return multipartEntity;
}

/**
 * Used to get a file name from a URI.
 *
 * @param uri     URI.
 * @param context Context.
 * @return File name from URI.
 */
public String getFileNameFromUri(final Uri uri, final Context context) {

    String fileName = null;
    if (uri != null) {
        // Get file name.
        // File Scheme.
        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
            File file = new File(uri.getPath());
            fileName = file.getName();
        }
        // Content Scheme.
        else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            Cursor returnCursor =
                    context.getContentResolver().query(uri, null, null, null, null);
            if (returnCursor != null && returnCursor.moveToFirst()) {
                int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                fileName = returnCursor.getString(nameIndex);
                returnCursor.close();
            }
        }
    }
    return fileName;
}

২. ইউআরআই থেকে বিটম্যাপ নেওয়া

যদি ইউআরআই চিত্রের দিকে ইশারা করে তবে আমরা বিটম্যাপ পাব, অন্যথায় নাল:

/**
 * Used to create bitmap for the given URI.
 * <p>
 * 1. Convert the given URI to bitmap.
 * 2. Calculate ratio (depending on bitmap size) on how much we need to subSample the original bitmap.
 * 3. Create bitmap bitmap depending on the ration from URI.
 * 4. Reference - http://stackoverflow.com/questions/3879992/how-to-get-bitmap-from-an-uri
 *
 * @param context       Context.
 * @param uri           URI to the file.
 * @param bitmapSize Bitmap size required in PX.
 * @return Bitmap bitmap created for the given URI.
 * @throws IOException
 */
public static Bitmap createBitmapFromUri(final Context context, Uri uri, final int bitmapSize) throws IOException {

    // 1. Convert the given URI to bitmap.
    InputStream input = context.getContentResolver().openInputStream(uri);
    BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
    onlyBoundsOptions.inJustDecodeBounds = true;
    onlyBoundsOptions.inDither = true;//optional
    onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
    BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
    input.close();
    if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
        return null;
    }

    // 2. Calculate ratio.
    int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;
    double ratio = (originalSize > bitmapSize) ? (originalSize / bitmapSize) : 1.0;

    // 3. Create bitmap.
    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
    bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
    bitmapOptions.inDither = true;//optional
    bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
    input = context.getContentResolver().openInputStream(uri);
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
    input.close();

    return bitmap;
}

/**
 * For Bitmap option inSampleSize - We need to give value in power of two.
 *
 * @param ratio Ratio to be rounded of to power of two.
 * @return Ratio rounded of to nearest power of two.
 */
private static int getPowerOfTwoForSampleRatio(final double ratio) {
    int k = Integer.highestOneBit((int) Math.floor(ratio));
    if (k == 0) return 1;
    else return k;
}

মন্তব্য

  1. অ্যান্ড্রয়েড ইউআরআই থেকে ফাইলের পাথ পেতে কোনও পদ্ধতি সরবরাহ করে না এবং উপরের উত্তরগুলির বেশিরভাগটিতে আমরা কয়েকটি ধ্রুবককে কঠোরভাবে কোড করেছি, যা বৈশিষ্ট্য প্রকাশে বিভক্ত হতে পারে (দুঃখিত, আমি ভুল হতে পারি)।
  2. কোনও ইউআরআই থেকে ফাইল পাথের সমাধানে সরাসরি যাওয়ার আগে, আপনি যদি ইউআরআই এবং অ্যান্ড্রয়েড ডিফল্ট পদ্ধতিতে আপনার ব্যবহারের ক্ষেত্রে সমাধান করতে পারেন তবে চেষ্টা করুন।

উল্লেখ

  1. https://developer.android.com/guide/topics/providers/content-provider-basics.html
  2. https://developer.android.com/reference/android/content/ContentResolver.html
  3. https://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/content/InputStreamBody.html

ধন্যবাদ. উরি এবং কন্টেন্ট রিসোলভারটি এভাবে ব্যবহার করা ফাইলগুলির সাথে কাজ করার সময় আমার অ্যাপ্লিকেশনটিকে উল্লেখযোগ্যভাবে সরল করে তুলেছে।
জ্যাকসোনাকজ

6

এই অ্যান্ড্রয়েড লাইব্রেরি কিটকাটের কেস পরিবর্তনগুলি পরিচালনা করে (পুরানো সংস্করণগুলি - ২.১+ সহ):
https://github.com/iPaulPro/aFileChooser

String path = FileUtils.getPath(context, uri)প্রত্যাশিত উরির সমস্ত ওএস সংস্করণে ব্যবহারযোগ্য একটি পাথ স্ট্রিংয়ে রূপান্তর করতে ব্যবহার করুন । এটি সম্পর্কে এখানে আরও দেখুন: https://stackoverflow.com/a/20559175/860488


3

যারা এখনও পল বার্কের কোডটি অ্যান্ড্রয়েড এসডিকে সংস্করণ ২৩ এবং তারপরে ব্যবহার করছেন, তাদের জন্য যদি আপনার প্রকল্পটি যদি এই বলে ত্রুটিটি পূরণ করে যে আপনি EXTERNAL_PERMISSION অনুপস্থিত রয়েছেন এবং আপনি নিশ্চিত হন যে আপনি ইতিমধ্যে আপনার AndroidManLive.xML ফাইলে ব্যবহারকারীর অনুমতি পেয়েছেন। এর কারণ আপনি অ্যান্ড্রয়েড এপিআই 23 বা তদুর্ধ্ব হতে পারেন এবং রানটাইমে ফাইলটি অ্যাক্সেস করার জন্য অ্যাকশনটি করার সময় গুগল আবার অনুমতিের নিশ্চয়তা দেওয়ার প্রয়োজন করে।

এর অর্থ: যদি আপনার এসডিকে সংস্করণটি 23 বা ততোধিক হয়, আপনি ছবি ফাইলটি নির্বাচন করার সময় আপনাকে READ & WRITE এর অনুমতি চাওয়া হবে এবং এর ইউআরআই জানতে চান।

এবং নীচে আমার কোড রয়েছে, পল বার্কের সমাধান ছাড়াও। আমি এই কোডগুলি যুক্ত করি এবং আমার প্রকল্পটি সূক্ষ্মভাবে কাজ শুরু করে।

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

আমার ক্ষেত্রে, কমপ্যাটুটিলস.জেভা হল যেখানে আমি যাচাই-বাছাইকরণের পদ্ধতিগুলি স্থির করি (স্ট্যাটিক টাইপ হিসাবে যাতে আমি এটিকে অন্যান্য ক্রিয়াকলাপের মধ্যে কল করতে পারি)।

এছাড়াও আপনি যদি ভেরিটিস্টোজারপিরমিশন পদ্ধতিতে কল করার আগে বর্তমান এসডিকে সংস্করণটি 23-এর উপরে আছে কি না তা দেখতে প্রথমে যদি কোনও রাজ্য তৈরি করেন তবে এটি আরও বোধ করা উচিত।


2

এই আমি কি কি:

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 থেকে প্রশ্ন অ্যান্ড্রয়েডে ইউরি.গেটপ্যাথ () দ্বারা সত্যিকারের পথ পান এবং আমি দাবি করি কোনও কৃতিত্ব নেই। আমি কেবল ভেবেছিলাম যে এই সমস্যাগুলি এখনও সমাধান করেন নি তারা এই ব্যবহার করতে পারে।


2
এটি কিটক্যাট-এ নতুন গ্যালারী অ্যাপের (কঠোরভাবে "মিডিয়া ডকুমেন্টস সরবরাহকারী" অ্যাপ্লিকেশন) এর উত্তর নয় to
nagoya0

প্রশ্নকর্তাকে যে অ্যাপ্লিকেশনটি "গ্যালারী" বলেছে সেটি সম্ভবত কিটকটে নতুন ফাইল চয়নকারী। এফওয়াইআই: addictivetips.com/android/…
nagoya0

আমি অনুরূপ করি এবং এই লাইনে নেক্সাস 5 এক্স, অ্যান্ড্রয়েড 6 এ সূচিপত্র আউটবাউন্ড পেয়েছি:cursor.getString(idx);

1

দয়া করে টেক পার্সেস্টেবল ইউরিপर्मিশন পদ্ধতিটি এড়াতে চেষ্টা করুন কারণ এটি আমার জন্য রানটাইম ব্যতিক্রম বাড়িয়েছে। / ** * গ্যালারী থেকে নির্বাচন করুন। * /

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

চিত্রের ডেটা হ্যান্ডেল করার জন্য ফলাফলের জন্যঅ্যাক্টিভিটি:

@ ওভাররাইড সুরক্ষিত অকার্যকার্য কার্যকলাপের ফলাফল (int অনুরোধ কোড, int ফলাফল কোড, ইনটেন্ট ডেটা) {

    //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();
        }


    }

দ্বিতীয় ক্ষেত্রে আপনি কোথায় চিত্রটি প্রদর্শন করছেন?
কোয়ান্টাম_ভিসি

দুঃখিত আমি এমআইএমজিক্রপিং.স্টার্টক্রপআইমেজ (ফটোফিল, অ্যাপকন্সট্যান্টস.আরএইকিইএসএসআইআইএমপিক্রোপি) যদি অন্য কোনও কোডের এই লাইনটি যুক্ত করতে ব্যর্থ হই; আমার প্রকল্পের প্রয়োজন অনুসারে আবার চিত্রক্রপিংয়ের ফাংশনটি কল করতে হবে
সরণ্য

ফটো ফাইল এবং এমআইএমজিক্রপিং কোন ফাইলের প্রকার?
ফিলিপ বিএইচ

1

কারও আগ্রহী হলে আমি এর জন্য একটি ওয়ার্কিং কোটলিন সংস্করণ তৈরি করেছি 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)
}

আমি শুধু কোটলিনের একটি ওয়ার্কিং কোড চাই। এটা আমার জন্য কাজ। ধন্যবাদ
হারভি সিরজা

1

আমি এখানে বেশ কয়েকটি উত্তর চেষ্টা করেছি এবং আমার মনে হয় আমার কাছে এমন একটি সমাধান রয়েছে যা প্রতিবার কাজ করবে এবং অনুমতিগুলিও পরিচালনা করবে।

এটি এলইও থেকে চালিত সমাধানের ভিত্তিতে তৈরি। এই পোস্টটিতে আপনার এই কাজটি করার জন্য প্রয়োজনীয় সমস্ত কোড থাকা উচিত এবং এটি কোনও ফোন এবং অ্যান্ড্রয়েড সংস্করণে কাজ করা উচিত;)

কোনও এসডি কার্ড থেকে একটি ফাইল বাছাই করার ক্ষমতা রাখার জন্য, আপনার নিজের প্রকাশ্যে এটি দরকার:

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

ধ্রুবক:

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

যদি সম্ভব হয় তবে অনুমতি এবং লঞ্চ আইমেজপিকটি পরীক্ষা করুন

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

অনুমতি প্রতিক্রিয়া

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

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

অনুমতি প্রতিক্রিয়া পরিচালনা করুন

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

চিত্র বাছাই শুরু করুন

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
}

চিত্র চয়ন প্রতিক্রিয়া পরিচালনা করুন

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

এটাই সব লোক; এটি আমার কাছে থাকা সমস্ত টেলিফোনে আমার জন্য কাজ করে।


0

এটি মোট হ্যাক, তবে আমি এখানে যা করেছি ...

সুতরাং ডকুমেন্টসপ্রাইডার সেটআপ করার সাথে সাথে আমি খেয়াল করেছি যে স্যাম্পল কোডটি (ইন getDocIdForFile450 লাইনের চারপাশে) আপনি প্রদত্ত নির্দিষ্ট মূলের সাথে সম্পর্কিত ফাইলের (অনন্য) পাথের উপর ভিত্তি করে নির্বাচিত নথির জন্য একটি অনন্য আইডি উত্পন্ন করে (এটি, আপনি কি সেটmBaseDir 96 লাইনে )।

সুতরাং ইউআরআই সমাপ্তির মতো কিছু দেখতে শুরু করে:

content://com.example.provider/document/root:path/to/the/file

যেমন ডকস বলেছেন, এটি কেবলমাত্র একটি একক রুট ধরেছে (আমার ক্ষেত্রে এটি Environment.getExternalStorageDirectory()তবে আপনি অন্য কোথাও ব্যবহার করতে পারেন ... তারপরে এটি রুট থেকে শুরু করে ফাইলের পথ নেয় এবং এটিকে অনন্য আইডি তৈরি করে, প্রিপেন্ডিং "। root:" তাই আমি "/document/root:"uri.getPath () থেকে অংশটি মুছে ফেলা, এই জাতীয় কিছু করে একটি আসল ফাইল পাথ তৈরি করে পথ নির্ধারণ করতে পারে :

public void onActivityResult(int requestCode, int resultCode, Intent data) {
// check resultcodes and such, then...
uri = data.getData();
if (uri.getAuthority().equals("com.example.provider"))  {
    String path = Environment.getExternalStorageDirectory(0.toString()
                 .concat("/")
                 .concat(uri.getPath().substring("/document/root:".length())));
    doSomethingWithThePath(path); }
else {
    // another provider (maybe a cloud-based service such as GDrive)
    // created this uri.  So handle it, or don't.  You can allow specific
    // local filesystem providers, filter non-filesystem path results, etc.
}

আমি জানি. এটা লজ্জাজনক, কিন্তু এটি কার্যকর। আবার এটি আপনার নিজের ব্যবহারের উপর নির্ভর করে ডকুমেন্ট আইডি তৈরি করতে এটি অ্যাপ্লিকেশনটিতে নথি সরবরাহকারী ।

(এছাড়াও, যে পথটি "/" ধরে না নেয় সেই পথটি তৈরি করার একটি আরও ভাল উপায় হ'ল পাথ বিভাজক ইত্যাদি But তবে আপনি ধারণাটি পেয়ে যান))


এমনকি একটি ক্রেজিয়ার চিন্তার সাথে আমার জবাব দেওয়ার জন্য - যদি আপনার অ্যাপ্লিকেশনটি ইতিমধ্যে file://কোনও বাহ্যিক ফাইল চয়নকারীর কাছ থেকে অভিপ্রায় পরিচালনা করছে , আপনি উপরোক্ত উদাহরণ হিসাবে এটিও আপনার কাস্টম সরবরাহকারীর কাছ থেকে নিশ্চিত করতে পারেন এবং যদি আপনি পারেন তবে file://আপনি যে পথটি বের করেছেন সেটিকে ব্যবহার করে একটি নতুন অভিপ্রায় "জালিয়াতি" করার পথটিও ব্যবহার করুন, তারপরে StartActivity()এবং আপনার অ্যাপ্লিকেশনটিকে এটি বাছাই করতে দিন। আমি জানি, ভয়ানক।
মোটা

0

এটি আমার পক্ষে ভাল কাজ করেছে:

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

ডাম্প আইমেজমেটাডাটা (ইউরি) ভুলে যান; এটি অপ্রয়োজনীয়
রাফা

0

পল বার্কের উত্তরের উপর ভিত্তি করে আমি বহিরাগত এসডি কার্ডের ইউআরআই পথটি সমাধান করতে অনেক সমস্যার মুখোমুখি হলাম কারণ বেশিরভাগ প্রস্তাবিত "বিল্ট-ইন" ফাংশনগুলি ফেরত পাঠায় যা ফাইলগুলিতে সমাধান হয় না।

যাইহোক, এই আমার হয় তার // করণীয় হ্যান্ডেল অ প্রাথমিক খন্ড পদ্ধতির

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

নোট করুন এটি হায়ারার্কির উপর নির্ভর করে যা প্রতিটি ফোন প্রস্তুতকারকের চেয়ে আলাদা হতে পারে - আমি সেগুলি সবই পরীক্ষা করে দেখিনি (এটি এতক্ষণে এক্সপিরিয়া জেড 3 এপিআই 23 এবং স্যামসাং গ্যালাক্সি এ 3 এপিআই 23 তে ভাল কাজ করেছে)।

এটি অন্য কোথাও ভাল না পারলে নিশ্চিত করুন confirm


-1

@ পল বার্কের উত্তর 19 এবং তদুর্ধের এপিআই স্তরের জন্য ক্যামেরা এবং গ্যালারী চিত্র উভয়ের জন্যই দুর্দান্ত কাজ করে তবে আপনার অ্যান্ড্রয়েড প্রকল্পের ন্যূনতম এসডিকে 19 এর নিচে সেট করা থাকলে এটি কার্যকর হয় না এবং উপরে উল্লিখিত কিছু উত্তর উভয় গ্যালারী এবং উভয়ের জন্যই কাজ করে না ক্যামেরা। ঠিক আছে, আমি @ পল বার্কের কোডটি সংশোধন করেছি যা এপিআই লেভেলের জন্য 19 এর নীচে কাজ করে Bel নীচে কোডটি রয়েছে।

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

আমি java.lang.IllegalArgumentException পেয়েছি: গুগল ডক ইমেজ নির্বাচন করার সময় অনুরোধ করা কলামগুলির
কোনওটিই

@ ডিরকোনিল আমিও একই ব্যতিক্রম পাচ্ছি। আপনি কি ঠিক করেছেন?
হেনরি

-4

আপনার প্রশ্নের উত্তর হ'ল আপনার অনুমতি থাকা দরকার। আপনার মেনিফেস্ট.এক্সএমএল ফাইলে নিম্নলিখিত কোডটি টাইপ করুন:

<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>`

এটি আমার জন্য কাজ করেছে ...

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.