Android技术咨询:相册图片保存至内部存储指定未创建文件夹
Hey Mohit! Let's fix your image saving logic so it creates the Shortcut/Images folder automatically and saves the selected photo properly across different Android devices. Here's the step-by-step implementation:
Key Issues in Your Current Code
- You're getting the image name too early (in
onCreate) — it won't capture the text the user types later. - Converting the image to a
Bitmapbefore saving risks OOM (Out of Memory) errors with large photos. - No logic to create the target folder if it doesn't exist.
Modified Full Code
Update your GetImage activity with these changes:
package com.example.mohitgupta.shortcut; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; import android.widget.ImageButton; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class GetImage extends AppCompatActivity { EditText imageName; private ImageButton img; private Uri selectedImage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_get_image); imageName = findViewById(R.id.ImageName); img = findViewById(R.id.imageSelected); // Initialize img here to avoid null pointers } public void GetImageIntent(View view) { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(intent, 1); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1 && resultCode == RESULT_OK && data != null) { selectedImage = data.getData(); img.setImageURI(selectedImage); } } public void SaveButtonClicked(View view) { // Get image name only when user clicks Save (captures latest input) String name = imageName.getText().toString().trim(); // Validate user input if (selectedImage == null) { Toast.makeText(this, "Please select an image first!", Toast.LENGTH_SHORT).show(); return; } if (name.isEmpty()) { Toast.makeText(this, "Please enter an image name!", Toast.LENGTH_SHORT).show(); return; } // Create target folder in app's private internal storage File targetFolder = new File(getFilesDir(), "Shortcut/Images"); if (!targetFolder.exists()) { boolean folderCreated = targetFolder.mkdirs(); // Creates nested folders if needed if (!folderCreated) { Toast.makeText(this, "Failed to create folder!", Toast.LENGTH_SHORT).show(); return; } } // Define target file (add .png extension; adjust for other formats if needed) File targetFile = new File(targetFolder, name + ".png"); // Save image by copying stream (memory-efficient, avoids OOM) try (InputStream inputStream = getContentResolver().openInputStream(selectedImage); OutputStream outputStream = new FileOutputStream(targetFile)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } Toast.makeText(this, "Image saved!\nPath: " + targetFile.getAbsolutePath(), Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, "Save failed: " + e.getMessage(), Toast.LENGTH_SHORT).show(); } } }
Explanation of Changes
1. Fix Image Name Timing
Moved the name variable to be fetched inside SaveButtonClicked, so it captures the text the user actually typed before clicking Save.
2. Auto-Create Target Folder
- Used
getFilesDir()to access the app's private internal storage (no extra permissions required, only your app can access this folder). targetFolder.mkdirs()creates the entire directory tree (bothShortcutandImagesif they don't exist).
3. Memory-Efficient Saving
Instead of converting the image to a Bitmap (which can crash with large photos), we directly copy the input stream from the selected Uri to the target file. This avoids OOM errors and uses less memory.
4. Error Handling & Feedback
- Added checks for missing image selection or empty file name.
- Showed clear success/failure toasts, including the full path of the saved image for verification.
- Used try-with-resources to auto-close streams, preventing resource leaks.
Optional: Save to External Storage (Public Access)
If you want the image to be visible in the device's file manager (not just app-private), use the app's external storage directory instead. Replace the targetFolder line with:
// Android 4.4+ (no permissions needed) File targetFolder = new File(getExternalFilesDir(null), "Shortcut/Images");
For Android 10+, saving to public folders (like Pictures/Shortcut/Images) requires using MediaStore instead of direct file access — let me know if you need that implementation!
Layout XML Note
Your existing layout is fine, but initializing the ImageButton in onCreate (as done in the code) prevents null pointer exceptions if the user clicks Save without selecting an image first.
内容的提问来源于stack exchange,提问作者Mohit

