Android기능_갤러리사진 픽(하나/다중)_PhotoView API_dot indicatorAPI_Camera취득사진

소정·2023년 3월 7일
1

Android_with_Java

목록 보기
25/34

[1] Gallery or Phto App으로 사진 선택


사진은 사진의 데이터 베이스의 주소를 줌 , 사진의 URI(contents) 주소를 줌 , 실제 주소가 아니다 디비의 리소스 주소

카메라 픽 5종류

  • 아무거나 써도 상관없다

카메라 사용 방법

  1. Glide API 사용

  2. 인텐트 생성 setType 필수!

    • MediaStore.ACTION_PICK_IMAGES = setType 필요없음
  3. 대행사 생성 (ActivityResultLauncher)

  4. 대행사에 런처 부탁~!

1. ACTION_PICK

  • 갤러리 및 포토 앱에서만 선택, 미디어파일 폴더에서만 찾아옴

2. ACTION_GET_CONTENT (구글 권장)

  • 모든 미디어 선택 앱에서 선택가능 (갤러리, 포토, 내문서 등)

3. ACTION_OPEN_DOCUMENT

  • 모든 문서 선택 앱에서 선택
    - GET_CONTENT의 대체품

4. Jetpack : PickVisualMediaRequest

  • 명시적인 Intent 생성없이 사진선택 화면이 BottomSheet 형식으로 보여짐

  • ActivityResultLauncher 가 다름 제네릭이 PickVisualMediaRequest로 온다


5. MediaStore.ACTION_PICK_IMAGES

  • MediaStore 객체의 액션 ACTION_PICK --> PickVisualMedia와 같은 역할을 해줌
  • Intent로 옴
  • setType 필요없음

1~5번 사용법 총 코드

package com.bsj0420.ex69photopickbyintent;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.PickVisualMediaRequest;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.net.URI;

public class MainActivity extends AppCompatActivity {

    TextView tv_uri;
    ImageView iv;

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

        tv_uri = findViewById(R.id.tv_uri);
        iv = findViewById(R.id.iv);

        findViewById(R.id.btn_pick).setOnClickListener(view -> clickPick());
        findViewById(R.id.btn_content).setOnClickListener(view -> clickContent());
        findViewById(R.id.btn_document).setOnClickListener(view -> clickDocument());
        findViewById(R.id.btn_pickVisualMedia).setOnClickListener(view -> clickPickVisualMedia());
        findViewById(R.id.btn_mediastore).setOnClickListener(view -> clickMediastore());
        
    }

    // 사진 선택 결과를 받아오는 계약을 체겨라는 개행사 객체 등록
    ActivityResultLauncher<Intent> imgPickResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            if(result.getResultCode() != RESULT_CANCELED) {
                //선택된 사진정보를 가진 택배기사 소환
                Intent intent = result.getData();
                //택배기사에게 사진정보 URI 데이터를 달라고 요첨
                Uri uri = intent.getData();
                tv_uri.setText(uri.toString());

                //이미지 뷰에 셋팅
                //이미지 로드 라이브러리 사용(Glide(범프테크 거), Picasso)
                Glide.with(MainActivity.this).load(uri).into(iv);
            }
        }
    });
    
    private void clickPick() {
        //ACTION_PICK : 갤러리 및 포토 앱에서만 선택, 미디어파일 폴더에서만 찾아옴
        Intent intent = new Intent(Intent.ACTION_PICK).setType("image/*");
        // setType(부를거/확장자) : 이거 안쓰면 에러 (* = 모든)

        imgPickResultLauncher.launch(intent);

    }

    private void clickContent() {
        //ACTION_GET_CONTENT : 모든 미디어 선택 앱에서 선택가능 (갤러리, 포토, 내문서 등)
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT).setType("image/*");
        imgPickResultLauncher.launch(intent);
    }

    private void clickDocument() {
        //ACTION_OPEN_DOCUMENT : 모든 문서 선택 앱에서 선택 - GET_CONTENT의 대체품
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("image/*");
        imgPickResultLauncher.launch(intent);

    }

    private void clickPickVisualMedia() {
        //명시적인 Intent 생성없이 사진선택 화면이 BottomSheet 형식으로 보여짐
        // PickVisualMedia
        pickMediaLauncher.launch(new PickVisualMediaRequest());

    }

    ActivityResultLauncher<PickVisualMediaRequest> pickMediaLauncher = registerForActivityResult(new ActivityResultContracts.PickVisualMedia(), new ActivityResultCallback<Uri>() {
        @Override
        public void onActivityResult(Uri result) { //곧바로 uri가 옴, 선택 안하면 null
            tv_uri.setText(result.toString());
            Glide.with(MainActivity.this).load(result).into(iv);
        }
    });

    private void clickMediastore() {
        //MediaStore 객체의 액션 ACTION_PICK --> PickVisualMedia와 같은 역할을 해줌
        Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES); //셋타입 필요없음
        imgPickResultLauncher.launch(intent);

    }
}



[1-1] PhotoView API : 사진 축소 확대

https://github.com/Baseflow/PhotoView
사진 확대 API 추가

PhotoView는 ImageView를 상속받아 만듦

0. 추가 방법

PhotoView 추가하면 아래와 같은 오류가 난다

gradle.properties 에서 android.enableJetifier=true 를 추가한다

  • 현재 최신 릴리즈번호는 2.30 인데 2.30 은 추가 하지 않아도 된다

화면에 적용 및 사용방법

그냥 기본 view처럼 사용하면 됨



[2] 사진 다중 선택(멀티픽)

사용방법

  1. 글라이더 추가
  2. 사진폴더에 접근 할 인텐트 생성
    .setType("가져올 애")
    .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) => 사진 다중선택 하겠다
  1. 대행사 생성 : ActivityResultLauncher
    -- result.getData() 한 애를
    -- ClipData로 받아야함

    💡 ClipData

    • ClipData란 선택한걸 저장 복사한 조그마한 저장소
    • ClipData은 사진만 선택하는 게 아니고 글자도 문서도 뭐든 올 수 있음
  2. 다중 선택한 사진을 보여주기 위해 uri 정보를 가진 arraylist와 이미지를 보여줄 layout을 만든 뒤 아답터에서 합쳐주고 리사이클러뷰나 뷰 페이저2로 보여줘야함

  3. main 런처에서 리스트에 add 해주고 아답터한테 데이터 추가 됐다고 알려주기 : notifyDataSetChanged()


1. ACTION_PICK/ ACTION_GET_CONTENT/ ACTION_OPEN_DOCUMENT 사용방법 같음

2. PickVisualMediaRequest

  • ActivityResultLauncher의 계약서 이름과 종류 잘 보기 (얘만 다름)

3. MediaStore.ACTION_PICK_IMAGES

  • 얘는 putExtra에 MediaStore.EXTRA_PICK_IMAGES_MAX 외대 개수 지정한다

총 코드

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_openDcu"
        android:text="action open document - multiple"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/btn_PickMultip"
        android:text="PickMultipleVisaul"
        android:layout_below="@+id/btn_openDcu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/btn_mediaStore"
        android:text="action MediaStorePiCK- multiple"
        android:layout_below="@+id/btn_PickMultip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>


    <TextView
        android:id="@+id/tv"
        android:padding="16dp"
        android:textColor="@color/black"
        android:layout_centerHorizontal="true"
        android:text="선택 개수"
        android:layout_below="@+id/btn_mediaStore"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/pager"
        android:layout_below="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator
        android:id="@+id/dots_indcator"
        android:clickable="true"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>

Main.java

package com.bsj0420.ex70phtomultipickbyintent;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.PickVisualMediaRequest;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;

import android.content.ClipData;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.TextView;

import com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    TextView tv;

    //이미지 담을 리스트
    ArrayList<Uri> uriArrayList = new ArrayList<>();
    ImgAdapter adapter;

    ViewPager2 pager;

    WormDotsIndicator dotsIndicator;

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

        tv = findViewById(R.id.tv);

        findViewById(R.id.btn_openDcu).setOnClickListener(v-> clickOpenDocu());
        findViewById(R.id.btn_PickMultip).setOnClickListener(v-> clickPickMulti());
        findViewById(R.id.btn_mediaStore).setOnClickListener(v-> clickMediaStore());

        //아답터 연결
        pager = findViewById(R.id.pager);
        adapter = new ImgAdapter(this,uriArrayList);
        pager.setAdapter(adapter);

        //인디 케이터 dots_indcator
        //dotsIndicator.attachTo(viewPager);
        dotsIndicator = findViewById(R.id.dots_indcator);
        dotsIndicator.attachTo(pager); // 연동 끝

    }

    //여러 사진 선택 결과를 돌려받는 계약 체결 대행사 객체 등록
    ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {

        if(result.getResultCode() != RESULT_CANCELED) { //취소하고 돌아오지 않을 때
            //사진 URI들 가져온 택배기사 소환
            Intent intent = result.getData();
            ClipData clipData = intent.getClipData();
            //ClipData : 선택한걸 저장 복사한 조그마한 저장소
            //ClipData은 사진만 선택하는 게 아니고 글자도 문서도 뭐든 올 수 있음

            int size = clipData.getItemCount(); //아이템 개수
            // clipData.getItemAt(0).getUri()
            // getItemAt 은 뭐든 올 수 있어서


            //uri 정보를 가진 item arraylist만들고 아답터로 만든 뒤 리사이클러뷰나 뷰 페이저2로 보여준다
            
            //!!이미지 셋!!
            for (int i=0; i <size; i++){
                uriArrayList.add( clipData.getItemAt(i).getUri() ); //
            }
            tv.setText("선택개수 : " + uriArrayList.size());

            //아답터한테 알려주기 - 화면 갱신~!
            adapter.notifyDataSetChanged();

            //인디케이터
            //원래는 탭으로 했는데 : dot indicator API 있음
        }

    });

    private void clickOpenDocu() {

        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("image/*").putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        resultLauncher.launch(intent);

    }

    private void clickPickMulti() {
        muliplePickLauncher.launch(new PickVisualMediaRequest());
    }

    ActivityResultLauncher<PickVisualMediaRequest> muliplePickLauncher = registerForActivityResult(new ActivityResultContracts.PickMultipleVisualMedia(), new ActivityResultCallback<List<Uri>>() {
        @Override
        public void onActivityResult(List<Uri> result) { //리스트로 옴

            for (Uri uri : result) {
                uriArrayList.add(uri);
            }
            tv.setText(uriArrayList.size() + "");
            adapter.notifyDataSetChanged();
            
        }
    });

    private void clickMediaStore() {
        //얘는 putExtra에 MediaStore.EXTRA_PICK_IMAGES_MAX 외대 개수 지정한다
        Intent intent = new Intent(MediaStore.ACTION_PICK_IMAGES).putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, 10);
        resultLauncher.launch(intent);

    }
}

ImageAdapter.java

package com.bsj0420.ex70phtomultipickbyintent;

import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;
import com.github.chrisbanes.photoview.PhotoView;

import java.util.ArrayList;

public class ImgAdapter extends RecyclerView.Adapter<ImgAdapter.VH> {

    Context context;
    ArrayList<Uri> items;

    public ImgAdapter(Context context, ArrayList<Uri> items) {
        this.context = context;
        this.items = items;
    }

    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.img_item,parent,false);
        return new VH(view);
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        //holder.photoView.setImageURI(items.get(position));
        Glide.with(context).load(items.get(position)).into(holder.photoView); //글라이더 쓰기
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    class VH extends RecyclerView.ViewHolder {

        PhotoView photoView;

        public VH(@NonNull View itemView) {
            super(itemView);

            photoView = itemView.findViewById(R.id.pv);
        }
    }
}

item.layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.github.chrisbanes.photoview.PhotoView
        android:id="@+id/pv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

[2-1] 💡 dot indicator API

https://github.com/tommybuonomo/dotsindicator

  • 스튜디오에 들어옴

레이아웃 화면

.java class

dotsIndicator.attachTo(viewPager2);



[3] Camera App으로 사진 선택

  • 요즘 핸드폰 프로그램으로 실행한 카메라앱에서 실행한 사진은 디바이스에 파일로 저장되지 않는다

1. 카메라로 찍은 사진 그냥 얻어오면 프리뷰 이미지로 오는 예제


->결과 화면의 화질이 떨어짐(프리뷰 화면이라)

  • 요즘 핸드폰 프로그램으로 실행한 카메라앱에서 실행한 사진은 디바이스에 파일로 저장되지 않는다
  • 촬영한 사진의 프리뷰(썸네일/작은 이미지) 정보(URL)를 Bitmap 객체로 만들어서 Extra 데이터로 전달해줌
package com.bsj0420.ex71cameraapp;

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

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    ImageView iv;

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

        iv = findViewById(R.id.iv);
        findViewById(R.id.camera_btn).setOnClickListener(v-> clickBtn());

    }

    private void clickBtn() {

        //카메라 앱 실행
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        resultLauncher.launch(intent);

    }

    ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {

        if(result.getResultCode() == RESULT_OK){
            // 사진 촬영 파일의 Uri 얻어오기
            Uri uri = result.getData().getData(); //앞 getData()는 Intent 뒤 getData()는 택배 박스
            if(uri == null) Toast.makeText(this, "null", Toast.LENGTH_SHORT).show();

            //요즘 핸드폰 프로그램으로 실행한 카메라앱에서 실행한 사진은 디바이스에 파일로 저장되지 않는다
            //촬영한 사진의 프리뷰(썸네일/작은 이미지) 정보(URL)를 Bitmap 객체로 만들어서 Extra 데이터로 전달해줌
            Intent intent = result.getData(); // 1. 인텐트 소환
            Bundle bundle=intent.getExtras(); // 2. 인텐트 한테 번들 꺼내옴
            Bitmap bm = (Bitmap)bundle.get("data"); // 3.비트맵으로 전환
            iv.setImageBitmap(bm); //4.이미지 뷰에 적용
            

        }

    });
}

2. **카메라로 찍은 사진 바로! 얻어오기

  • 개발자가 file로 저장되길 원한다면 인텐트로 카메라 앱을 실행 할 때 추가 데이터를 설정해야함
  • 중요 촬영한 이미지를 file로 저장하도록 추가데이터로 [저장될 이미지의 Uri] 설정

** URI(실제 경로) 구하기 : 콘텐츠 경로 - DB경로

0단계. 저장될 정보 구하기

  • 촬영한 이미지가 저장될 파일의 Uri (콘텐츠 경로 - DB경로)
  1. 이미지 경로 참조 변수 생성
  2. 인텐트에 엑스트라(putExtra) 주려면 imgUri이 필요해서 만들러 가자
  3. 개발자가 저장되길 원하는 위치에 파일 경로 URI를 만들어주는 기능(자체 제작) 호출
    3-1) 이미지의 경로 Uri를 생성하는 기능 메소드 설계

1단계. 이미지 폴더 저장경로

외부 저장소의 앱 전용 영역에 저장해 볼것임

2단계. 파일명 각각 다르게 저장

이름이 동일하면 덮어쓰기가 되므로 이름의 겹치지 않도록하기
보통 : 오늘 날짜 - 시분초 이용

  1. SimpleDateFormat으로 패턴 정하기
  2. 파일명 만들기

3단계. File 클래스에 경로 + 파일명.확장자 합체

4단계. 실제 경로(File 클래스 객체)를 콘텐츠 경로(Uri 객체)로 변환 : FileProvider 이용

  • 누각 버전부터 다른앱이 내 DB 못 건드림
  • 다른 앱에게 파일의 접근을 허용하려면 Contents Provider 를 이용해야됨 (나의 DB정보를 다른 앱에게 주는 것, 내 앱 공개자)
  • Provider는 4대 컴포넌트 이기에 class에 상속받아 만들어야함
  • But Provider 중 파일에 대한 경로 제공 Provider은 이미 클래스로 설계되어 있다 : FileProvider

매니패스트에 등록

  • 꼭 스타트 엔드로 나눠서 만들어야됨
  • authorities : 유일키(보통 패키지명)
  • name : 클래스이름
  • exported : 절대 열어두면 안됨 false! (필수)
  • grantUriPermissions : 임시퍼미션 해주겠다 (필수)

메타 데이터 만들기
이 프로 바이더가 공개 할 경로 지정

  • name : 지정되어 있음 못 바꿈 android.support.FILE_PROVIDER_PATHS
  • resource : 공개할 파일 경로 xml에 써두겠다
  • Root element : paths 로 지정

res - xml - paths.xml

매니패스트.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- API 28버전 이하는 외부 저장소에 대한 '동적 퍼미션' 필요하다 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Ex72CameraApp_real"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <!-- 파일 프로바이더 등록
        authorities : 유일키(보통 패키지명)
        name : 클래스이름
        꼭 스타트 엔드로 나눠서 만들어야됨
        exported : 절대 열어두면 안됨 false! (필수)
        grantUriPermissions : 임시퍼미션 해주겠다 (필수)
        -->
        <provider
            android:authorities="sam"
            android:name="androidx.core.content.FileProvider"
            android:exported="false"
            android:grantUriPermissions="true">

            <!-- 이 프로 바이더가 공개 할 경로 지정
            name : 지정되어 있음 못 바꿈 android.support.FILE_PROVIDER_PATHS
            resource : 공개할 파일 경로 어딘가에 써두겠다
            -->
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/paths"/>

        </provider>
        
    </application>

</manifest>

5단계. imgUri에 저장된 카메라 앱이 촬영한 이미지를 ActivityResultLauncher에서 받아옴

결과 화면


uri 경로가 content로 시작되면 잘 한것임!!

main.java 총 소스코드

package com.bsj0420.ex72cameraapp_real;

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

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {

    ImageView iv;
    TextView tv;

    //촬영한 이미지가 저장될 파일의 Uri (콘텐츠 경로 - DB경로)
    //1. 이미지 경로 참조 변수
    Uri imgUri = null;

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

        //개발자가 file로 저장되길 원한다면
        //인텐트로 카메라 앱을 실행 할 때 추가 데이터를 설정해야함


        iv = findViewById(R.id.iv);
        tv = findViewById(R.id.tv);

        findViewById(R.id.btn).setOnClickListener(view -> clickBtn());

    }

    private void clickBtn() {

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //카메라 앱 실행 인텐트

        //3. 개발자가 저장되길 원하는 위치에 파일 경로 URI를 만들어주는 기능(자체 제작) 호출
        cerateImageUri();

        
        //**중요** 촬영한 이미지를 file로 저장하도록 추가데이터로 [저장될 이미지의 Uri] 설정
        //외부메모리 안에 공용폴더 중 픽쳐스 안에 파일 저장해보기
        //2. 엑스트라에 주려면 imgUri이 필요해서 만들러 가자
        if(imgUri != null) intent.putExtra(MediaStore.EXTRA_OUTPUT,imgUri); //imgUri가 Null이면 오류나서 if문 처리
        
        
        resultLauncher.launch(intent);

    }

    //결과 받아오는 대행사
    ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {

        if(result.getResultCode() == RESULT_OK){
            //카메라 앱이 촬영한 이미지를 EXTRA_OUTPUT 으로 지정한 imgUri에 저장했을 것임
            Glide.with(this).load(imgUri).into(iv);
        }

    });


    //3-1) 이미지의 경로 Uri를 생성사는 기능 메소드 설계
    private void cerateImageUri() {
        //저장될 파일의 경로 지정
        //외부 저장소에 저장
        //1. 외부 저장소의 앱 전용 영역
        //2. 외부저장소의 미디어 영역

        //1. 외부 저장소의 앱 전용 영역
        File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        // getExternalStoragePublicDirectory은 이미지 폴더 같은 잘 알려진 곳

        tv.setText(path.toString()); //=> 결과 :

        //2) 파일명
        //이름이 동일하면 덮어쓰기가 되므로 이름의 겹치지 않도록하기
        //보통 : 오늘 날짜 - 시분초 이용
        //String fileName = "Ex72_IMG_2023030713470.jpg";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmms"); //오늘날짜 년월일 시분초

        String fileName = "Ex72_"+ sdf.format(new Date()) + ".jpg";

        //3) 경로 + 파일명.확장자
        File file = new File(path + fileName);  //실제 경로
        tv.setText(file.toString());

        //4) 카메라앱은 저장될 이미지의 실제 경로가 아니라 DB주소에 해당하는
        // 콘텐츠 경로가 필요하다
        //이 콘텐츠 경로를 Uri라고 부름
        
        //실제 경로(File 클래스 객체)를 콘텐츠 경로(Uri 객체)로 변환
        //누각 버전부터 다른앱에 DB 못 건드림
        // Contents Provider (나의 DB정보를 다른 앱에게 주는 것) 사용해야됨!
        // 다른 앱에게 파일의 접근을 허용하려면 Provider를 이용해야됨
        // 그 중에서 파일에 대한 경로 제공 Provider은 이미 클래스로 설계되어 있다
        // FileProvider
        
        imgUri = FileProvider.getUriForFile(this,"sam",file);
        //FileProvider.getUriForFile(contet, 제공하는자-암거나 써도 되나 디바이스 안에 유일해야함 보톤 패키지 이름씀 , file)

        tv.setText(imgUri.toString());

    }

}
profile
보조기억장치

0개의 댓글