먼저 TedPermission(권한 관리 라이브러리), Glide, 권한을 각각 등록해준다.
// app gradle implementation 'gun0912.ted:tedpermission:2.2.1' implementation 'com.github.bumptech.glide:glide:4.8.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0' // manifest <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
동기화가 완료되었으면 main activity에 Tedpermission을 불러와 권한 체크를 한다.
// onCreate TedPermission.with(this) .setPermissionListener(permissionListener) .setDeniedMessage("권한이 거부되었습니다. 사용을 원하시면 설정에서 해당 권한을 직접 허용해주세요.") .setPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE) .check(); // Listner PermissionListener permissionListener = new PermissionListener() { @Override public void onPermissionGranted() { // 권한 승낙 후 로직 작성 부분 } @Override public void onPermissionDenied(List<String> deniedPermissions) { Toast.makeText(SmartIdActivity.this, "권한이 승인되지 않은 경우, 예기치 않은 오류가 발생할 수 있습니다.", Toast.LENGTH_LONG).show(); } };
사진을 불러와서 보여줄 로직을 수행할 액티비티에서 버튼, 이미지뷰를 불러온 후 다음과 같은 메소드들을 등록한다.
// requestCode private static final int PROFILE_PICTURE = 0; // file path private String filePath; // onCreate filePath = SharedUtil.getString(getApplicationContext(), "imgPath"); if (!TextUtils.isEmpty(filePath)) { Glide.with(this).asBitmap().load(filePath).into(mIvProfile); } else { // 파일 경로가 없는 경우, 보여줄 기본 이미지 Glide.with(this).load(R.drawable.no_profile).into(mIvProfile); } mBtnReg.setOnClickListener(v -> selectGallery()); // methods public void selectGallery() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); // 외부 저장소에 있는 이미지 파일들에 대한 모든 정보를 얻을 수 있다. intent.setType("image/*"); // image/* 형식의 Type 호출 -> 파일을 열 수 있는 앱들이 나열된다. startActivityForResult(intent, PROFILE_PICTURE); } public void getPic(Uri imgUri) { String imgPath = getRealPathFromURI(imgUri); // SharedPreferences 관리 Class : 해당 내용은 블로그에 있으니 참조 SharedUtil.putString(getApplicationContext(), "imgPath", imgPath); Glide.with(this).asBitmap().load(imgPath).into(mIvProfile); } public String getRealPathFromURI(Uri uri) { int index = 0; String[] proj = {MediaStore.Images.Media.DATA}; // 이미지 경로로 해당 이미지에 대한 정보를 가지고 있는 cursor 호출 Cursor cursor = getContentResolver().query(uri, proj, null, null, null); // 데이터가 있으면(가장 처음에 위치한 레코드를 가리킴) if (cursor.moveToFirst()) { // 해당 필드의 인덱스를 반환하고, 존재하지 않을 경우 예외를 발생시킨다. index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); } Log.d("getRealPathFromURI", "getRealPathFromURI: " + cursor.getString(index)); return cursor.getString(index); } //onActivityResult @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case PROFILE_PICTURE: if (data != null) { getPic(data.getData()); } else { return; } break; } }
2019. 01. 09 수정 사항
cursor에 대한 Null Check를 수행하지 않아 NPE가 발생되어 앱이 Crash되는 현상이 발생하였다.
cursor의 Null Check와 close를 꼭 처리하자.
*getRealPathFromURI 메소드는 삭제하고 다음과 같이 진행한다.
public void selectGallery(Activity activity) { Intent intent = new Intent(Intent.ACTION_PICK); intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); intent.setType("image/*"); activity.startActivityForResult(intent, PROFILE_PICTURE); } //MVP로 리팩토링함(이전 소스와 view 메소드 이름을 참고해서 수정하면 된다) private void getPicture(Context context, Uri uri){ int index = 0; String[] proj = {MediaStore.Images.Media.DATA}; Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); if(cursor == null){ view.showToast("사진이 없습니다."); view.setInitProfile(); } else if (cursor.moveToFirst()) { index = cursor.getColumnIndex(MediaStore.Images.Media.DATA); String imgPath = cursor.getString(index); setData(context, "imgPath", imgPath); view.setProfile(imgPath); Log.d("realPathFromURI", "realPathFromURI: " + imgPath); cursor.close(); }else{ view.showToast("커서가 비었습니다."); view.setInitProfile(); cursor.close(); } }
2020. 08. 07 수정 사항
Q(=29) 버전부터는 외부저장소에 Scoped Storage 개념이 적용되어 외부 저장소의 파일을 읽거나 쓰는 기능에 제한을 두게 되었다.
이에 대응한 게시글의 링크를 첨부한다.
'Before 2022 > Android' 카테고리의 다른 글
위젯에서 glide 사용하기 (0) | 2018.08.29 |
---|---|
안드로이드 Spinner onItemSelected 반복 호출 문제 (0) | 2018.08.28 |
Edittext InputFilter로 한글 및 영어만 입력 시키기 (0) | 2018.08.24 |
안드로이드 Notification 클래스로 관리하기(알림, 브로드캐스트) (0) | 2018.08.24 |
SharedPreferences 클래스로 관리하기 (0) | 2018.08.24 |