[JAVA] * Android * Saving / loading images to external storage

Introduction

Hello. Continuing from Last time, we will explain Android storage operations. This time, the content is to save / load images to the external storage, but I will try to realize it in a way as close as possible to the previous saving / reading of files to the external storage.

As I mentioned every time, the content of each article about Android commentary is slightly different, and I think that some people may get lost, so I try to write a standard method.

Premise

The development environment is as follows. *Android Studio 4.0.1 *targetSdkVersion 28 *Google Nexus 5x

Save / load images to external storage

The story of saving to external storage previous has been described in detail, so I will omit it. This time as well, we will deal with reading and writing to the application-specific area of the external storage.

Saving image files to external storage

The explanation is based on the assumption that an asset folder is created under the main directory of Android and picture.jpg is placed. The asset folder is created by right-clicking ** [main] → [New] → [Folder] → [Assets Folder] **.

Now, get the path to the folder you want to save in the external storage and create the path including the file name.

this.imgName = "picture.jpg ";
this.path = getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString();
this.file = this.path + "/" + this.fileName;

As a result, the character string "/sdcard/Android/data/package name/files/PICTURES/picture.jpg " is assigned to the file variable.

Next, read the image file from the Asset folder.

AssetManager assetManager = getResources().getAssets();
InputStream inputStream = assetManager.open(imgName);

Save the read image file in the external storage. The byte array of the image file is acquired by ```inputStream.read (buffer) `` `. The byte array is written to a file that saves 1024 bytes in external storage.

FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
while (true){
    int len = inputStream.read(buffer);
    if (len < 0){
        break;
    }
    fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.flush();

Reading image files from external storage

To load an image, open the stream with the InputStream type. Then, use `BitmapFactory.decodeStream ()` to get the image as `Bitmap``` type. After that, set it to ```imageView``` with setImageBitmap () ``.

InputStream inputStream = new FileInputStream(file);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
imageView.setImageBitmap(bitmap);

Sample code

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.keita.myapplication">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:text="Save File"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="Read File"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button1" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="fitCenter"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.2"/>

</android.support.constraint.ConstraintLayout>

MainActivity.java


package com.example.keita.myapplication;

import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {
    private String file;
    private String path;
    public String state;
    private String imgName = "picture.jpg ";
    private Button button1;
    private Button button2;
    public ImageView imageView;
    private final String[] PERMISSIONS = {
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    private final int REQUEST_PERMISSION = 1000;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.button1 = findViewById(R.id.button1);
        this.button2 = findViewById(R.id.button2);
        this.imageView = findViewById(R.id.imageView);
        this.path = getExternalFilesDir(Environment.DIRECTORY_PICTURES).toString();
        this.file = this.path + "/" + this.imgName;

        checkPermission();
    }

    private void checkPermission(){
        if (isGranted()){
            setEvent();
        }
        else {
            requestPermissions(PERMISSIONS, REQUEST_PERMISSION);
        }
    }


    private boolean isGranted(){
        for (int i = 0; i < PERMISSIONS.length; i++){
            //The first time is PERMISSION_DENIED returns
            if (checkSelfPermission(PERMISSIONS[i]) != PackageManager.PERMISSION_GRANTED) {
                //Returns true if the request is rejected once. Returns false for the first time or when "Do not show again" is selected.
                if (shouldShowRequestPermissionRationale(PERMISSIONS[i])) {
                    Toast.makeText(this, "Permission required to run the app", Toast.LENGTH_LONG).show();
                }
                return false;
            }
        }
        return true;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION){
            checkPermission();
        }
    }


    private void setEvent(){
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                state = Environment.getExternalStorageState();
                if (Environment.MEDIA_MOUNTED.equals(state)){
                    saveFile(file);
                }
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                state = Environment.getExternalStorageState();
                if (Environment.MEDIA_MOUNTED.equals(state)){
                    readFile(file);
                }
            }
        });
    }


    private void saveFile(String file){
        try {
            AssetManager assetManager = getResources().getAssets();
            InputStream inputStream = assetManager.open(imgName);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            while (true){
                int len = inputStream.read(buffer);
                if (len < 0){
                    break;
                }
                fileOutputStream.write(buffer, 0, len);
            }
            fileOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private void readFile(String file){
        try {
            InputStream inputStream = new FileInputStream(file);
            Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
            imageView.setImageBitmap(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Recommended Posts

* Android * Saving / loading images to external storage
* Android * Saving / loading files to internal storage
POST images from Android to PHP using Retrofit
How to link images using FactoryBot Active Storage
[Android] Uploading images from your device to the server
[Rails 6] Add images to seed files (using Active Storage)
Android app to select and display images from the gallery
Zip and upload multiple files to Firebase Storage on Android.