Paramclasses Academy - Blog

Tutorials Details

←
Post 29 of 40
→

How to Use Camera, Gallery and File Storage in Android Apps with Java ?

How to Use Camera, Gallery and File Storage in Android Apps with Java ?

November 4, 2026

1. Introduction

Modern Android applications often need access to photos and files stored on a mobile device.

For example:

  • A social media app allows users to upload profile pictures.

  • A camera app captures and saves photographs.

  • A shopping app allows users to upload product images.

  • A document management app allows users to select and store files.

Android provides different APIs to capture photos, select images and save application files.

In this tutorial, we will create a practical Photo Capture App using Android Studio and Java.

Our application will allow users to:

  1. Capture a photo using the camera.

  2. Select an existing photo from the gallery.

  3. Display the selected photo in an ImageView.

  4. Save a copy of the selected photo in app-specific storage.

  5. View the saved image inside the application.

2. Understanding Camera, Gallery and File Storage

Before writing code, let's understand the three main concepts.

A. Camera

The camera allows users to capture new photographs using their mobile device.

Android provides camera intents that allow an application to open an available camera application.

We can use ActivityResultContracts.TakePicture() to capture a full-size image at a specified URI.

B. Gallery

The gallery contains images stored on the device or available through supported media providers.

Android provides the Photo Picker and other system file-selection interfaces.

We will use ActivityResultContracts.GetContent() to allow users to select an image.

C. File Storage

Android provides different storage locations for application files.

Two important options are:

Internal Storage:

  • Private to the application.

  • Other applications generally cannot access these files directly.

  • Files are removed when the application is uninstalled.

App-Specific External Storage:

  • Stores application files in an app-specific directory on external storage.

  • Does not require general storage permission for the app's own directory.

  • Files are also removed when the application is uninstalled.

In this tutorial, we will save photos in the app-specific Pictures directory.

3. Requirements

Make sure you have:

  1. Android Studio installed.

  2. Java programming language.

  3. An Android Emulator or real Android phone.

  4. A camera-enabled device or emulator camera configuration.

4. Create a New Android Studio Project

Follow these steps:

  1. Open Android Studio.

  2. Click New Project.

  3. Select Empty Views Activity.

  4. Enter the project name:

PhotoCaptureApp
  1. Select Java as the programming language.

  2. Choose your minimum SDK.

  3. Click Finish.

Wait until Gradle synchronization completes.

5. Configure Android Dependencies

Open the app-level Gradle file:

app/build.gradle

Make sure the project has AndroidX Activity and Core dependencies.

For a Groovy Gradle project, add these inside the dependencies block if they are not already available through existing dependencies:

dependencies {

    implementation 'androidx.activity:activity:1.10.1'

    implementation 'androidx.core:core:1.15.0'

}

Keep compatible versions if your project already uses newer versions.

Click Sync Now.

These libraries provide Activity Result APIs and FileProvider functionality.

6. Design the Application Screen

Open:

app > res > layout > activity_main.xml

Replace the existing layout with:

<?xml version="1.0" encoding="utf-8"?>

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="20dp">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Photo Capture App"
            android:textSize="25sp"
            android:textStyle="bold"
            android:gravity="center"
            android:layout_marginBottom="20dp" />

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="280dp"
            android:scaleType="fitCenter"
            android:background="#EEEEEE"
            android:contentDescription="Selected photo" />

        <Button
            android:id="@+id/btnCamera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Capture Photo"
            android:layout_marginTop="20dp" />

        <Button
            android:id="@+id/btnGallery"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Select from Gallery" />

        <Button
            android:id="@+id/btnSave"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Save Selected Photo" />

        <TextView
            android:id="@+id/txtResult"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="No photo selected"
            android:textSize="15sp"
            android:layout_marginTop="15dp" />

    </LinearLayout>

</ScrollView>

Understanding the Layout

  • imageView displays the selected or captured photo.

  • btnCamera opens the camera.

  • btnGallery opens the image selection interface.

  • btnSave saves a selected gallery image into app-specific storage.

  • txtResult displays the operation result.

7. Configure FileProvider

When an application shares a file with another application, it should use a content URI instead of exposing a direct file path.

Android provides FileProvider for this purpose.

We will use it to share the destination image URI with the camera application.

Step 1: Add FileProvider to AndroidManifest.xml

Open:

app > manifests > AndroidManifest.xml

Inside the <application> element, add:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">

    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />

</provider>

Do not add this provider outside the application element.

Step 2: Create file_paths.xml

Open:

app > res

If the xml folder does not exist:

  1. Right-click the res folder.

  2. Select New.

  3. Select Android Resource Directory.

  4. Set Resource Type to xml.

  5. Click OK.

Inside the xml folder, create:

file_paths.xml

Add this code:

<?xml version="1.0" encoding="utf-8"?>

<paths xmlns:android="http://schemas.android.com/apk/res/android">

    <external-files-path
        name="external_images"
        path="Pictures/" />

    <files-path
        name="internal_images"
        path="Pictures/" />

</paths>

These paths allow FileProvider to share files stored in the application's Pictures directories.

8. Understand Camera and Gallery Permissions

For this implementation:

  • We do not need to request general gallery storage permission because the user selects an image through the system content picker.

  • We do not need CAMERA permission because we launch an external camera application through an intent.

  • We do not need general storage permission to write inside our own app-specific directory.

This is an important Android privacy practice: request only the access that your application actually needs.

9. Write Java Code for Camera, Gallery and Storage

Open:

app > java > your_package_name > MainActivity.java

Replace the existing code with:

package com.example.photocaptureapp;

import android.net.Uri;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;

public class MainActivity extends AppCompatActivity {

    ImageView imageView;

    Button btnCamera, btnGallery, btnSave;

    TextView txtResult;

    Uri cameraImageUri;
    Uri selectedImageUri;

    File cameraImageFile;

    ActivityResultLauncher<Uri> cameraLauncher;

    ActivityResultLauncher<String> galleryLauncher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);

        btnCamera = findViewById(R.id.btnCamera);
        btnGallery = findViewById(R.id.btnGallery);
        btnSave = findViewById(R.id.btnSave);

        txtResult = findViewById(R.id.txtResult);

        // Camera result launcher
        cameraLauncher = registerForActivityResult(
                new ActivityResultContracts.TakePicture(),
                success -> {

                    if (success && cameraImageUri != null) {

                        selectedImageUri = cameraImageUri;

                        imageView.setImageURI(cameraImageUri);

                        txtResult.setText(
                                "Photo captured and saved in app storage"
                        );

                        Toast.makeText(
                                this,
                                "Photo captured successfully",
                                Toast.LENGTH_SHORT
                        ).show();

                    } else {

                        txtResult.setText("Camera operation cancelled");

                        if (cameraImageFile != null) {
                            cameraImageFile.delete();
                        }
                    }
                }
        );

        // Gallery result launcher
        galleryLauncher = registerForActivityResult(
                new ActivityResultContracts.GetContent(),
                uri -> {

                    if (uri != null) {

                        selectedImageUri = uri;

                        imageView.setImageURI(uri);

                        txtResult.setText(
                                "Photo selected from gallery"
                        );

                    }
                }
        );

        // Open camera
        btnCamera.setOnClickListener(v -> openCamera());

        // Open gallery
        btnGallery.setOnClickListener(v -> {

            galleryLauncher.launch("image/*");

        });

        // Save selected photo
        btnSave.setOnClickListener(v -> saveSelectedPhoto());
    }

    private File getImageDirectory() {

        File directory = getExternalFilesDir("Pictures");

        if (directory == null) {

            directory = new File(
                    getFilesDir(),
                    "Pictures"
            );
        }

        if (!directory.exists()) {
            directory.mkdirs();
        }

        return directory;
    }

    private void openCamera() {

        try {

            cameraImageFile = File.createTempFile(
                    "IMG_",
                    ".jpg",
                    getImageDirectory()
            );

            cameraImageUri = FileProvider.getUriForFile(
                    this,
                    getPackageName() + ".provider",
                    cameraImageFile
            );

            cameraLauncher.launch(cameraImageUri);

        } catch (Exception e) {

            Toast.makeText(
                    this,
                    "Unable to open camera: " + e.getMessage(),
                    Toast.LENGTH_LONG
            ).show();
        }
    }

    private void saveSelectedPhoto() {

        if (selectedImageUri == null) {

            Toast.makeText(
                    this,
                    "Please capture or select a photo first",
                    Toast.LENGTH_SHORT
            ).show();

            return;
        }

        try {

            File destinationFile = File.createTempFile(
                    "SAVED_",
                    ".jpg",
                    getImageDirectory()
            );

            try (
                    InputStream inputStream =
                            getContentResolver().openInputStream(
                                    selectedImageUri
                            );

                    OutputStream outputStream =
                            new FileOutputStream(destinationFile)
            ) {

                if (inputStream == null) {
                    throw new Exception("Unable to open selected image");
                }

                byte[] buffer = new byte[8192];

                int bytesRead;

                while ((bytesRead = inputStream.read(buffer)) != -1) {

                    outputStream.write(buffer, 0, bytesRead);
                }

                outputStream.flush();
            }

            Toast.makeText(
                    this,
                    "Photo saved successfully",
                    Toast.LENGTH_LONG
            ).show();

            txtResult.setText(
                    "Saved file: " + destinationFile.getName()
            );

        } catch (Exception e) {

            Toast.makeText(
                    this,
                    "Save failed: " + e.getMessage(),
                    Toast.LENGTH_LONG
            ).show();
        }
    }
}

Important: Replace the package declaration with the package name generated by your Android Studio project.

10. Understand the Important Java Code

A. ActivityResultLauncher

ActivityResultLauncher<Uri> cameraLauncher;

This launcher starts an external camera activity and receives the result.

The ActivityResultContracts.TakePicture() contract accepts an output URI and returns a Boolean indicating whether the image was successfully captured.

B. Open the Camera

cameraLauncher.launch(cameraImageUri);

This launches the camera application and tells it where to save the full-size image.

C. Select an Image from Gallery

galleryLauncher.launch("image/*");

This opens the system content picker and allows the user to select an image.

The image/* MIME type means that the application accepts image files.

D. Display the Selected Image

imageView.setImageURI(uri);

This displays the selected image in the ImageView.

E. Create an App-Specific Directory

File directory = getExternalFilesDir("Pictures");

This returns the application's Pictures directory in app-specific external storage.

F. Generate a Content URI

cameraImageUri = FileProvider.getUriForFile(
        this,
        getPackageName() + ".provider",
        cameraImageFile
);

This creates a secure content URI for sharing the camera output file.

G. Copy an Image into Storage

inputStream = getContentResolver().openInputStream(selectedImageUri);

This opens the selected image for reading.

outputStream.write(buffer, 0, bytesRead);

This copies the image data into the destination file.

11. Understand the Application File Structure

Your project should now contain:

PhotoCaptureApp/
    app/
        src/
            main/
                java/
                    MainActivity.java

                res/
                    layout/
                        activity_main.xml

                    xml/
                        file_paths.xml

                AndroidManifest.xml

        google-services.json (not required for this project)

The google-services.json file is not required because this application does not use Firebase.

12. Run and Test the Application

Follow these steps:

Step 1: Run the Application

Connect your Android phone or start an emulator.

Click the Run button in Android Studio.

Step 2: Test Camera

  1. Click Capture Photo.

  2. The camera application will open.

  3. Capture a photograph.

  4. Confirm the photo.

  5. Return to the Android application.

The captured image should appear in the ImageView.

Step 3: Test Gallery

  1. Click Select from Gallery.

  2. The system image picker will open.

  3. Select an image.

  4. Return to the application.

The selected image should appear in the ImageView.

Step 4: Test File Storage

  1. Select an image from the gallery.

  2. Click Save Selected Photo.

  3. Wait for the success message.

The image will be copied to the application's Pictures directory.

Step 5: Verify Saved Files

Open Android Studio.

Go to:

View > Tool Windows > Device Explorer

Browse to your application's external app-specific storage directory:

Android/data/your.package.name/files/Pictures/

You should find the captured and saved image files.

The exact directory may vary depending on the device and Android version.

13. Important Difference Between Gallery URI and Stored File

When a user selects an image from the gallery, Android generally returns a content URI.

Example:

content://media/external/images/media/123

This URI identifies the selected content.

It is not necessarily a direct filesystem path.

Our application uses:

getContentResolver().openInputStream(uri);

to read the image.

We then copy it into our own app-specific directory.

This approach avoids relying on inaccessible or guessed filesystem paths.

14. Common Errors and Their Solutions

Error 1: FileProvider IllegalArgumentException

Problem: The application cannot generate a content URI.

Solution:

  • Check the provider authority.

  • Verify the FileProvider entry in AndroidManifest.xml.

  • Check the file_paths.xml resource.

  • Ensure that the destination file is inside an allowed directory.

Error 2: Camera Does Not Open

Problem: The device does not have an available camera application or camera activity.

Solution: Test on a real device or configure a camera-enabled emulator.

Error 3: Image Not Displaying

Problem: The image URI cannot be read.

Solution: Check the URI and use ContentResolver to access its stream.

Error 4: File Not Saved

Problem: The destination directory cannot be created or written.

Solution: Check the app-specific storage location and handle the file operation exception.

Error 5: Gallery Image Not Accessible Later

Problem: The application tries to reuse a temporary content URI after its access permission is no longer available.

Solution: Copy the selected image into app-specific storage when long-term access is needed.

15. Best Practices for Camera and File Storage

Follow these practices when developing real Android applications:

  1. Use Activity Result APIs instead of deprecated activity result methods.

  2. Prefer the Android Photo Picker for selecting images.

  3. Use FileProvider when sharing files with other applications.

  4. Avoid exposing direct filesystem paths.

  5. Save private application files in app-specific storage.

  6. Handle large images efficiently to avoid memory errors.

  7. Do not request unnecessary storage permissions.

  8. Handle camera cancellation and file errors.

  9. Use appropriate image compression when storing large photographs.

  10. Use shared MediaStore storage if photos need to appear in the device's public gallery.

16. Conclusion

In this tutorial, we created a Photo Capture App using Android Studio and Java.

We learned how to:

  • Open the camera application.

  • Capture full-size photos.

  • Select images from the gallery.

  • Display images using ImageView.

  • Use Activity Result APIs.

  • Configure Android FileProvider.

  • Generate secure content URIs.

  • Copy images into app-specific storage.

  • Inspect application files using Android Studio Device Explorer.

Camera, gallery and file storage are important features in many real-world Android applications.

17. Frequently Asked Questions

Q1. How can an Android application open the camera?

An Android application can use ActivityResultContracts.TakePicture() to launch an available camera application and save the captured image to a specified URI.

Q2. What is FileProvider?

FileProvider is an Android component that generates secure content URIs for sharing files between applications.

Q3. What is the difference between a file path and a URI?

A file path identifies a file in a filesystem, while a URI identifies a resource that an application can access through a content provider or another supported mechanism.

Q4. Do we need storage permission to select a gallery image?

When using the system Photo Picker or content picker, the user grants access to the selected image. General gallery storage permission is not required for this workflow.

Q5. What is app-specific storage?

App-specific storage is a location reserved for files belonging to an application. These files are removed when the application is uninstalled.

Q6. What is the difference between internal and app-specific external storage?

Internal storage is private application storage managed within the app's internal data area. App-specific external storage is located in the application's dedicated external storage directory. Neither requires general storage permission for the app's own files.

Q7. Can we save a selected gallery image permanently?

Yes. Copy the image into app-specific storage or use an appropriate shared storage location if the image needs to remain accessible outside the application.

←
Post 29 of 40
→