본문 바로가기
카테고리 없음

[Android][Java] 내부저장소에 사진 저장하기

by teamnova 2023. 10. 26.
728x90

안녕하세요 오늘은 내부저장소에 사진을 저장하고 저장한 사진을 불러오는 예제를 만들어 보겠습니다.

 

내부저장소란?

앱이 설치된 기기 내부에 있는 저장 공간을 의미합니다. 

 

안드로이드 공식문서에는 아래와 같이 설명되어 있습니다.

  • 내부 저장소 디렉터리: 이 디렉터리에는 영구 파일을 저장하는 전용 위치와 캐시 데이터를 저장하는 위치가 모두 포함되어 있습니다. 시스템은 다른 앱에서 이러한 위치에 액세스하는 것을 방지하고, Android 10(API 수준 29) 이상에서는 이러한 위치가 암호화됩니다. 이와 같은 특성으로 인해 앱 자체에서만 액세스할 수 있는 민감한 정보를 저장하기에 좋습니다.

https://developer.android.com/training/data-storage/app-specific?hl=ko

 

앱별 파일에 액세스  |  Android 개발자  |  Android Developers

DataStore는 로컬 데이터를 저장하는 최신 방법을 제공합니다. SharedPreferences 대신 DataStore를 사용해야 합니다. 자세한 내용은 DataStore 가이드를 참고하세요. 앱별 파일에 액세스 컬렉션을 사용해 정

developer.android.com

 

먼저 Java파일입니다.

MainActivity

public class MainActivity extends AppCompatActivity {
    Button selecBtn;  // 선택 버튼
    Button Check;  // 확인 버튼
    String time = get_now_time();  // 현재 시간을 가져옴
    ImageView imageView;  // 이미지를 보여줄 ImageView
    private final String FileName = time + ".png";  // 현재 시간을 이용한 파일명 생성
    String ImageName;  // 이미지 파일명을 저장할 변수

    // 액티비티 생성 시 호출되는 메서드
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView = findViewById(R.id.imageView);  // ImageView 초기화
        selecBtn = findViewById(R.id.selecBtn);  // 선택 버튼 초기화
        Check = findViewById(R.id.Check);  // 확인 버튼 초기화

        // "Check" 버튼에 대한 클릭 이벤트 리스너 설정
        Check.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // MainActivity2로 이동하는 Intent 생성 및 이미지 파일명 전달
                Intent intent = new Intent(MainActivity.this, MainActivity2.class);
                intent.putExtra("ImgName", ImageName);
                startActivity(intent);
            }
        });

        // "selecBtn" 버튼에 대한 클릭 이벤트 리스너 설정
        selecBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_PICK);  // 갤러리에서 이미지를 선택하는 Intent 생성
                intent.setType(MediaStore.Images.Media.CONTENT_TYPE);
                intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);
                intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                activityResultLauncher.launch(intent);  // 선택한 이미지를 처리하는 ActivityResultLauncher 실행
            }
        });
    }

    // ActivityResultLauncher를 초기화하고 결과를 처리하는 콜백 메서드 설정
    ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == RESULT_OK) {
                        if (result.getData() != null) {
                            Intent intent = result.getData();
                            Uri fileUri = intent.getData();  // 선택한 이미지의 URI 가져오기
                            ContentResolver resolver = getContentResolver();  // ContentResolver로 이미지 데이터 읽기
                            try {
                                InputStream inputStream = resolver.openInputStream(fileUri);  // InputStream을 이용하여 이미지 읽기
                                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);  // InputStream을 Bitmap으로 변환
                                inputStream.close();  // InputStream 닫기
                                imageView.setImageURI(fileUri);  // ImageView에 선택한 이미지 설정
                                saveImage(bitmap);  // 선택한 이미지를 저장하는 메서드 호출
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    );

    // 이미지를 저장하는 메서드
    private void saveImage(Bitmap bitmap) {
        ImageName = FileName;  // 이미지 파일명을 현재 시간으로 설정
        File file = new File(getCacheDir(), ImageName);  // 파일 경로 설정

        try {
            file.createNewFile();  // 새 파일 생성
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);  // 비트맵 이미지를 파일로 압축하여 저장
            out.close();  // 출력 스트림 닫기
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 현재 시간을 문자열 형태로 반환하는 메서드
    private String get_now_time() {
        long now = System.currentTimeMillis();  // 현재 시간을 가져온다.
        Date mDate = new Date(now);  // Date형식으로 고친다.
        // 날짜, 시간을 가져오고 싶은 형태로 가져올 수 있다.
        @SuppressLint("SimpleDateFormat")
        SimpleDateFormat simpleDate = new SimpleDateFormat("yyyyMMddhhmmss", Locale.KOREA);
        String now_time = simpleDate.format(mDate);  // 포맷에 맞게 변환한 현재 시간을 반환
        return now_time;
    }
}

MainActivity 2 

public class MainActivity2 extends AppCompatActivity {

    ImageView imageView3;  // 이미지를 보여줄 ImageView

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

        imageView3 = findViewById(R.id.imageView3);  // ImageView 초기화

        String imgPath = getIntent().getStringExtra("ImgName");  // MainActivity에서 전달된 이미지 파일명을 받아옴

        try {
            String path = getCacheDir() + "/" + imgPath;  // 내부 저장소의 경로에 이미지 파일명을 포함하여 경로 생성
            Bitmap bitmap = BitmapFactory.decodeFile(path);  // 경로로부터 이미지 파일을 읽어와 Bitmap으로 변환
            imageView3.setImageBitmap(bitmap);  // ImageView에 Bitmap 설정하여 이미지를 보여줌
        } catch (Exception e) {
            e.printStackTrace();  // 예외 발생 시 스택 트레이스 출력
        }
    }
}

activity_main xml 파일

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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/selecBtn"
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:background="#ffffff"
        android:text="이미지 선택"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/selecBtn"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/Check"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_main2

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity2">

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

 

%

실행했을때 

애뮬레이터 /data/data/package이름/cache 에 가보시면 저장된 것을 확인할 수 있습니다.

 

실행 화면입니다.