पर्यावरण .getExternalStorageDirectory () एपीआई स्तर 29 जावा में पदावनत


109

एंड्रॉइड जावा पर काम करना, हाल ही में अपडेट किए गए एसडीके को एपीआई स्तर 29 में दिखाया गया है, जिसमें चेतावनी दी गई है जो बताता है कि

Environment.getExternalStorageDirectory() एपीआई स्तर 29 में पदावनत किया गया है

मेरा कोड है

private void saveImage() {

if (requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

    final String folderPath = Environment.getExternalStorageDirectory() + "/PhotoEditors";
    File folder = new File(folderPath);
    if (!folder.exists()) {
        File wallpaperDirectory = new File(folderPath);
        wallpaperDirectory.mkdirs();
    }


    showLoading("Saving...");
    final String filepath=folderPath
                + File.separator + ""
                + System.currentTimeMillis() + ".png";
    File file = new File(filepath);

    try {
        file.createNewFile();
        SaveSettings saveSettings = new SaveSettings.Builder()
                .setClearViewsEnabled(true)
                .setTransparencyEnabled(true)
                .build();
        if(isStoragePermissionGranted() ) {
            mPhotoEditor.saveAsFile(file.getAbsolutePath(), saveSettings, new PhotoEditor.OnSaveListener() {
            @Override
            public void onSuccess(@NonNull String imagePath) {
                hideLoading();
                showSnackbar("Image Saved Successfully");
                mPhotoEditorView.getSource().setImageURI(Uri.fromFile(new File(imagePath)));
                sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,Uri.fromFile(new File(filepath))));
                Intent intent = new Intent(EditImageActivity.this, StartActivity.class);
                startActivity(intent);
                finish();

            } 

            @Override
            public void onFailure(@NonNull Exception exception) {
                hideLoading();
                showSnackbar("Failed to save Image");
            }
       });
   }

इसके लिए क्या विकल्प होगा?

जवाबों:


108

के बजाय का उपयोग करें getExternalFilesDir(), getExternalCacheDir()या getExternalMediaDirs()(तरीकों पर Context) Environment.getExternalStorageDirectory()

या, फिर, के mPhotoEditorसाथ काम करने में सक्षम होने के लिए संशोधित करें Uri:

  • का प्रयोग करें ACTION_CREATE_DOCUMENTएक पाने के लिए Uriउपयोगकर्ता के चुने गए स्थान के लिए, या

  • एक विशेष प्रकार के मीडिया (जैसे, एक छवि) के लिए उपयोग करें MediaStore, ContentResolverऔर insert()प्राप्त करने के लिए Uri- इस नमूना ऐप को देखें जो वेब साइट से MP4 वीडियो डाउनलोड करने के लिए ऐसा करता है

इसके अलावा, ध्यान दें कि आपके Uri.fromFileसाथ ACTION_MEDIA_SCANNER_SCAN_FILEएंड्रॉइड 7.0+ पर दुर्घटनाग्रस्त होना चाहिए FileUriExposedException। Android Q पर, केवल MediaStore/ insert()विकल्प से आपकी सामग्री MediaStoreजल्दी से अनुक्रमित हो जाएगी ।

ध्यान दें कि आप एंड्रॉइड 10 और 11 पर इन "स्कोप्ड स्टोरेज" बदलावों का विकल्प चुन सकते हैं, यदि आपका तत्व targetSdkVersion30 से नीचे है , तो मैनिफ़ेस्ट android:requestLegacyExternalStorage="true"के <application>तत्व का उपयोग करके । यह एक दीर्घकालिक समाधान नहीं है , क्योंकि targetSdkVersion2021 में आपके पास 30 या उससे अधिक होने की आवश्यकता होगी यदि आप अपने ऐप को प्ले स्टोर (और शायद कहीं और) के माध्यम से वितरित कर रहे हैं।


12
प्रिय @CommonsWare, क्या हमें कभी वास्तविक जीवन में मिलना चाहिए, कृपया मुझे याद दिलाएं कि मैं आपको अपने ब्लॉग पोस्ट के लिए बीयर देने वाला हूं। मैंने पूरी दोपहर यह जानने में बिताई कि एक निश्चित बाहरी पुस्तकालय ने काम करना क्यों बंद कर दिया है, जैसे ही मैंने लक्ष्यस्कैड स्तर को बढ़ाकर 29 कर दिया। अब मुझे पता है कि क्यों ...
नान्तोका

1
getExternalFilesDir () और getExternalCacheDir () का उपयोग करके api 29 के साथ काम कर सकते हैं, लेकिन जब ऐप unistalled सभी डेटा को इस विधियों का उपयोग करके हटा दिया जाएगा ... यदि आप इस विशेषता का उपयोग एप्लिकेशन टैग "android: requestLegemExternalStorage =" true "" api के लिए भी कर सकते हैं २ ९। जब ऐप अनलिस्टेड फ़ाइल नाम बाहर निकलता है, लेकिन डेटा हटा दिया जाता है
Ucdemir

1
@miladsalimi: क्षमा करें, लेकिन मुझे आपका प्रश्न समझ में नहीं आया। मेरा सुझाव है कि आप एक अलग स्टैक ओवरफ्लो प्रश्न पूछें जहां आप विस्तार से बताते हैं कि आपकी चिंता क्या है।
कॉमन्सवेयर

3
कोई है getExternalMediaDirमें Context, यह अपने आप को देखें: developer.android.com/reference/android/content/Context और getExternalMediaDirsअनुचित बताया गया है, यह भी देखने के: developer.android.com/reference/android/content/... दोनों getExternalFilesDir()और getExternalCacheDir()आवेदन की स्थापना रद्द करें पर नष्ट हो जाती हैं ( एक ही URL देखें)। इसलिए, उपरोक्त में से कोई भी स्थानापन्न नहीं हो सकता है Environment.getExternalStorageDirectory()
मंद

1
यह मेरा usecase के बारे में नहीं है, लेकिन ऊपर विषय के usecase है।
डिम

33

जाओ destPathनई API कॉल के साथ:

String destPath = mContext.getExternalFilesDir(null).getAbsolutePath();

3
हम इस विधि का उपयोग कर सकते हैं: developer.android.com/training/data-storage/… ? आपने इस बारे में क्या सोचा ? :)
एरोक्स

2
अभी भी वातावरण चर getExternalFilesDir (Environment.DIRECTORY_DOWNLOADS) प्राप्त कर सकते हैं की जगह Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DOWNLOADS)
रोवन बेरी

इस FIXED "अनुमति से वंचित" पदावनत विधि अद्यतित करें 29 संग्रहण बाह्य लक्ष्यीकरण के लिए createNewFile से त्रुटि! धन्यवाद!
Coolcool1994

यह सार्वजनिक निर्देशिका नहीं है
इरफान उल हक

25

Android Q के लिए, आप android:requestLegacyExternalStorage="true"अपने तत्व को मेनिफ़ेस्ट में जोड़ सकते हैं । यह विकल्प चुनता विरासत भंडारण मॉडल में आप हैं और अपनी मौजूदा बाह्य भंडारण कोड काम करेंगे।

<manifest ... >
<!-- This attribute is "false" by default on apps targeting
     Android 10 or higher. -->
  <application android:requestLegacyExternalStorage="true" ... >
    ...
  </application>
</manifest>

तकनीकी रूप से, आपको केवल एक बार अपने targetSdkVersion29 को अपडेट targetSdkVersionकरने के लिए इसकी आवश्यकता android:requestLegacyExternalStorage="false"होती है। कम वैल्यू वाले एप्स जो कि लीगेसी स्टोरेज में ऑप्‍टेट करने के लिए डिफाल्‍ट होते हैं और इसे ऑप्ट आउट करना होगा ।


1
इस पोस्ट ने एंड्रॉइड स्टूडियो के नवीनतम संस्करण में बाहरी भंडारण पर डेटा संग्रहीत करने के समाधान के लिए मेरी खोज को पहले विकसित कोड के साथ सहेजा है - जो 8 घंटे तक चला था। धन्यवाद।
श्रीराम नादिमिंटि

1
यह एपीआई 29 तक काम करेगा। "सावधानी: एंड्रॉइड 11 (एपीआई स्तर 30) को लक्षित करने के लिए अपने ऐप को अपडेट करने के बाद, सिस्टम अनुरोध को अनदेखा करता है जब आपका ऐप एंड्रॉइड 11 उपकरणों पर चल रहा हो, तो आपका ऐप स्कॉप्ड का समर्थन करने के लिए तैयार होना चाहिए। भंडारण और उन उपकरणों पर उपयोगकर्ताओं के लिए ऐप डेटा स्थानांतरित करने के लिए। " developer.android.com/training/data-storage/use-cases
avisper

अभी भी एक ही त्रुटि हो रही है
ओलाजाइड

6

कृपया का उपयोग करें getExternalFilesDir(), getExternalCacheDir()बजाय Environment.getExternalStorageDirectory()जब आप एंड्रॉयड 10 में फ़ाइल बनाने।

नीचे पंक्ति देखें:

val file = File(this.externalCacheDir!!.absolutePath, "/your_file_name")

1
नमस्ते, हम getExternalFilesDir()छवि को बचाने के लिए कस्टम पथ के साथ कैसे उपयोग कर सकते हैं , मैं इसका उपयोग गैलरी में छवियों को रोकने के लिए करना चाहता हूं? डिफॉल्ट में यह सेवAndorid/data/packagename/...
मिल्ड सलिमी

आपको ऐप डायरेक्टरी में फाइल को सेव करना होगा और फिर मीडिया यूरी का उपयोग करके इसे
डालना होगा

6
गलत उत्तर .. सटीक सवाल / कैसे प्राप्त करें / संग्रहण / उत्सर्जित / 0 / MyFolder / लेकिन आपका anser /data/user/0/com.example.package/files/MyFolder
तारिफ चकर

5

यह एक छोटा सा उदाहरण है कि किसी फ़ाइल के लिए URI कैसे प्राप्त करें यदि आप डिफ़ॉल्ट कैमरे का उपयोग करके फोटो लेना चाहते हैं और इसे DCIM फ़ोल्डर (DCIM / app_name / filename.jpg) में संग्रहीत करें:

खुला कैमरा (CAMERA अनुमति के बारे में याद रखें):

private var photoURI: Uri? = null

private fun openCamera() {
    Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
        photoURI = getPhotoFileUri()
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
        takePictureIntent.resolveActivity(requireActivity().packageManager)?.also {
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
        }
    }
}

और URI प्राप्त करें:

private fun getPhotoFileUri(): Uri {
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
    val fileName = "IMG_${timeStamp}.jpg"

    var uri: Uri? = null
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val resolver = requireContext().contentResolver
        val contentValues = ContentValues().apply {
            put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
            put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/app_name/")
        }

        uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
    }

    return uri ?: getUriForPreQ(fileName)
}

private fun getUriForPreQ(fileName: String): Uri {
    val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
    val photoFile = File(dir, "/app_name/$fileName")
    if (photoFile.parentFile?.exists() == false) photoFile.parentFile?.mkdir()
    return FileProvider.getUriForFile(
        requireContext(),
        "ru.app_name.fileprovider",
        photoFile
    )
}

पूर्व क्यू के लिए WRITE_EXTERNAL_STORAGE अनुमति के बारे में मत भूलना और AndroidManifest.xml में एक FileProvider जोड़ें।

और एक परिणाम प्राप्त करें:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    when (requestCode) {
        REQUEST_IMAGE_CAPTURE -> {
            photoURI?.let {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    val thumbnail: Bitmap =
                        requireContext().contentResolver.loadThumbnail(
                            it, Size(640, 480), null
                        )
                } else {
                    // pre Q actions
                }
            }
        }
    }
}

यह भी पदावनत किया गया है
लियोनार्डो हेनाओ

1
कृपया इसे जावा पोस्ट करें
अत्तुल्लाह

5

इसने मेरे लिए काम किया

manifestफ़ाइल के एप्लिकेशन टैग में इस लाइन को जोड़ें

android:requestLegacyExternalStorage="true"

उदाहरण

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:requestLegacyExternalStorage="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

 </application>

लक्ष्य एसडीके 29 है

  defaultConfig {
        minSdkVersion 16
        targetSdkVersion 29
        multiDexEnabled true
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

1
इस टिप्पणी का डुप्लिकेट: stackoverflow.com/a/61774820/7487335
जोश कोर्रेया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.