일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 함수형 프로그래밍
- 캐치마인드
- 끝말잇기
- 프래그먼트
- 재택근무
- 베드트레이
- 커스텀린트
- 리얼하다
- 베드테이블
- 테트리스
- 한단어의힘
- T자형인재
- 어떻게 나답게 살 것인가
- 면접
- 목적중심리더십
- 안드로이드
- 1일1커밋
- 아비투스
- 북한살둘레길
- 목적 중심 리더십
- 지지않는다는말
- 한달독서
- 슬기로운 온라인 게임
- 소프시스 밤부 좌식 엑슬 테이블
- 자취필수템
- 소프시스
- 한달브런치북만들기
- 브런치작가되기
- 한달어스
- 좌식테이블
- Today
- Total
정상에서 IT를 외치다
카메라 예제와 함께 보는 Scoped Storage (저장소의 종류) 본문
안녕하세요. 블랙진입니다.
Scoped Storage 대응에 앞서 기존 안드로이드 저장소가 어떻게 구성되어 있는지 살펴보겠습니다.
<카메라 예제와 함께 보는 Scoped Storage>
내부저장소
App을 설치하게 되면 앱 자신만 사용할 수 있는 공간인 내부저장소가 생깁니다. 이 저장소에는 cache, files 등의 폴더가 자동으로 생성되며 read/write 에 대해 어떠한 권한도 필요하지 않습니다. 그리고 앱이 삭제 되면 함께 제거됩니다.
android:allowBackup="true"
참고) 만일 AndroidManifest에 allowBackup이 true로 설정되어 있다면(default) 앱 정보를 구글 클라우드에 저장하게 됩니다. 이렇게 되면 앱을 재설치 했을 때 클라우드에서 데이터를 복원하기 때문에 내부 저장소에 데이터가 살아있게 됩니다.
위치
로그를 통해 저장소 위치를 확인해 보겠습니다.
Timber.e("--내부 저장소--")
Timber.d("getFileDir : ${filesDir.absolutePath}")
Timber.d("getCacheDir : ${cacheDir.absolutePath}")
> getFileDir : /data/user/0/com.tistory.blackjin.storeapplicaion/files
> getCacheDir : /data/user/0/com.tistory.blackjin.storeapplicaion/cache
저장소 위치는 Device File Explorer를 통해 확인할 수 있습니다.
shift를 연속 두번 누르면 위 화면이 나옵니다.
코드와 이미지를 비교해서 보겠습니다. 경로 표시에 약간의 차이는 있으나 data 폴더 안에 package 명으로 폴더가 생성되며 files와 cache 폴더가 생성되는 것을 직접 확인하실 수 있습니다.
외부저장소
외부저장소는 App 전용 폴더와 공용 폴더 두 부분으로 나눠집니다.
App 전용 공간
내부저장소와 비슷합니다. 앱 마다 고유의 공간을 가지고 있고 권한 없이 read/write 가능하며 앱이 삭제되면 함께 제거됩니다. 또한 다른 앱들은 자신의 데이터 폴더에 접근 할 수 없습니다. 하지만 FileProvider를 사용해 uri를 넘길 수 있습니다. (뒤에 있을 카메라 예제의 경우 App 전용 폴더에 있는 파일의 uri를 넘길 수 있습니다.)
android:allowBackup="true"
여기도 마찬가지로 allowBackup 영향을 받습니다.
로그를 통해 저장소 위치를 확인해 보겠습니다.
Timber.e("--외부 앱 전용 공간--")
Timber.d("getExternalCacheDir : ${externalCacheDir?.absolutePath}")
Timber.d("getExternalFilesDir : ${getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath}")
> getExternalCacheDir : /storage/emulated/0/Android/data/com.tistory.blackjin.storeapplicaion/cache
> getExternalFilesDir : /storage/emulated/0/Android/data/com.tistory.blackjin.storeapplicaion/files/Pictures
저장소 위치를 Device File Explorer를 통해 직접 확인해 볼까요?
경로는 storage > self > primary > Android >data > package 명으로 생성되는 것을 확인하실 수 있습니다.
> 여기까지는 안드로이드Q 저장소 정책에 대응할 필요가 없고 접근 권한 또한 요구하지 않습니다. 다음부터 나오는 공용 공간부터는 안드로이드Q 정책에 맞춰야 하며 파일에 대한 접근 권한 또한 받아야 합니다.
공용 공간
공용 폴더는 앱 삭제 여부와 상관없이 계속 남아있으며 다른 앱들간의 공유가 이뤄집니다. 여기서는 read/write 사용시 아래 두가지 권한을 런타임에 사용자 동의를 받아야 합니다.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
로그를 통해 저장소 위치를 확인해 보겠습니다.
Timber.e("--외부 저장소--")
Timber.d("getExternalStorageDirectory1 : ${Environment.getExternalStorageDirectory()}")
Timber.d(
"getExternalStorageDirectory2 : ${Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES
)}"
)
> getExternalStorageDirectory1 : /storage/emulated/0
> getExternalStorageDirectory2 : /storage/emulated/0/Pictures
경로는 storage > self > primary 아래에 파일들이 저장되게 됩니다. 만일 제가 blackJin이라는 폴더를 생성했다면 아래와 같이 확인할 수 있습니다.
blackJin이라는 폴더가 생성되었죠? 이 폴더에 들어간 데이터는 해당 앱 설치 유무와 상관없이 존재하게 되며 다른 앱 들이 접근 할 수 있습니다.
예제
조금더 이해를 돕기 위해 내부저장소에 txt를 저장하고 불러오는 예제를 하나 만들어 보겠습니다.
//Device File Explorer 통해 정보를 확인할 수 있다.
val fileName = "blackJin"
//만일 경로를 내부저장소가 아닌 외부저장소로 하면 해당 폴더에 파일을 생성합니다.
val innerDir = File(filesDir.absolutePath)
val innerFile = File.createTempFile(fileName, ".txt", innerDir)
val fos = FileOutputStream(innerFile)
val writer = BufferedWriter(OutputStreamWriter(fos))
writer.write("BlackJin Hello")
writer.flush()
writer.close()
fos.close()
val strBuffer = StringBuffer()
val `is` = FileInputStream(innerFile)
val reader = BufferedReader(InputStreamReader(`is`))
val read = strBuffer.append(reader.readLine())
reader.close()
`is`.close()
이렇게 코드를 실행하게 되면 data 폴더안에 blackJin.txt 파일이 만들어지는걸 확인하실 수 있습니다.
<참고 사이트>
'안드로이드' 카테고리의 다른 글
[Android] Customing BottomNavView (0) | 2019.11.27 |
---|---|
[Android, BottomSheet] 안드로이드 버텀 시트 사용 (0) | 2019.11.24 |
카메라 예제와 함께 보는 Scoped Storage (권한 가져오기) (0) | 2019.11.15 |
안드로이드 Q 주요 이슈 사항 간략 정리 (0) | 2019.11.15 |
[Dagger] Dagger step3 - Subcomponent와 scope (0) | 2019.09.16 |