티스토리 뷰
안드로이드의 외장 공간이란?
public static File getExternalStorageDirectory()
이 함수는 외장 메모리 디렉토리를 리턴한다. 다른 컴퓨터에 의해서 외장 메모리가 연결되었거나, 디바이스로부터 외장 메모리가 제거된경우, 또다른 문제가 발생한 경우 이 외장 메모리 디렉토리를 접근할수없다.
따라서, 현재 외장 메모리를 이용할수 있는가를 getExternalStorageState() 메서드로 다음과 같이 확인을 먼저 해줘야 한다.
1 2 | if (Environment.MEDIA_MOUNTED.equals(state)){ //외장 메모리가 제대로 연결 되었는가? Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //카메라 앱 실행 | cs |
외장 메모리 공간은 공개 되어 있는 공간이며 USB에 연결되어 쉽게 수정/이동/삭제가 가능한 공간을 의미한다.
외장 메모리 = 공유 메모리 라고 생각하는것이 편하다. 외장메모리는 단순히 SD카드를 의미하지는 않는다.
SD카드 뿐만 아니라 디바이스 내에 이미 설치된 제거될수없는 저장공간도 외장 메모리로 불린다.(빌트인 외장 스토리지)
즉, 핸드폰에는 시스템에 의해서 보호되는 내장 스토리지와 그렇지 않고 공유될수있는 외장 메모리로 구분되는데, 외장 메모리는 SD카드와 빌트인된 외장 메모리 2가지를 의미한다.
Device Storage
Internal Storage
External Storage
- Built in non-removable storage
- SD card
이런식으로 구성되어 있는 셈이다.
(Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected internal storage and can be mounted as a filesystem on a computer.)
안드로이드는 왜 외부 저장 공간을 만들었을까?
안드로이드는 이미 앱을 위한 효율적인 내장 스토리지를 제공하고 있으나, 다음과 같은 상황 때문에 외장 스토리지를 추가로 제공하게 되었다.
1. 좀 더 큰 파일을 저장하기 위한 좀 더 큰 메모리와 디스크 공간
2. 다른 앱에 의해서 접근되어야 하는 내 앱의 파일들을 저장해야 하는 공간이 필요 (공유 디렉토리)
3. 내 앱이 제거 되더라도 지워지지 말아야 할 데이터가 있기 때문이다. 내 엡에 의해서 다운된 사진이나 비디오는 이 앱이 삭제 될떄 같이 지워지면 안될것이다.
안드로이드의 외부 저장 공간을 얻는 API를 살펴보자
Main APIs for Android external storage.
Environment.getExternalStorageDirectory()
: return the primary external storage root directory.Context.getExternalFilesDir(String type)
: return the absolute path of the directory on the primaryexternal storage where the application can place its own files.Context.getExternalCacheDir()
| return reference to your application specific path of cache directory on external storage.Environment.getExternalStoragePublicDirectory(String type)
| return public external storage directory for saving files of a particular type.
Following figure gives an overview of Android external storage APIs.
이전 포스트에서도 언급한적이 있던것 같은데, 이 그림이 좀 더 자세히 나와 있다. Movies 디렉토리는 여러 앱들끼리 공유할수 있는 공유 디렉토리이다. 이곳에 저장되는 파일들은 앱이 지워진다고해서 파일이 같이 삭제되지 않는다.
하지만 <your_app_package> 하위에 존재하는 모든 디렉토리들은 앱이 지워지면 같이 지워지는 디렉토리들이다.
이전 포스트에서 언급했던것과 같이 <your_app_package>에 해당하는 부분이 앱 홈 폴더이다.
참고)
이 xml파일은 FileProvider가 Content Uri를 생성 할 수 있는 디렉토리의 path들을 명시한 파일이다. 이 곳에 적혀진 디렉토리내의 파일에 대해서만 content uri를 생성하여 외부에 공개할수있다. 각 엘리먼트는 오른쪽에 나와있는 주석에 해당하는 경로를 나타낸다.
Environment.getExternalStorageDirectory()
이 메소드는 기본 외장 스토리지의 탑레벨 디렉토리를 리턴한다. 만약 디바이스가 여러개의 외장 스토리지를 갖고 있다면 이 메소드로 리턴되는 외장 스토리지는 유저와 상호작용하게될 기본 외장 스토리지이다. 즉 여러개의 외장 스토리지중 대표 하나의 디렉토리 패스만 리턴 된다는것.
Context.getExternalFilesDirs(String type)
Context.getExternalCacheDirs()
Context.getExternalMediaDirs()
위의 3개의 메소드를 사용하게 되면 기본 외장 스토리지가 아닌 세컨더리 스토리지에 엑세스 하거나 리스트를 가져올수있다.
현재 내엡에서 이 탑레벨 디렉토리에 파일을 저장하는일을 막아야 한다. 앱 끼리 공유해야할 필요가 있는 파일이라면 getExternalStoragePublicDirectory()를 통해 나오는 디렉토리에 저장하고 그렇지 않고 앱 내부에서만 사용할 파일이라면 getExternalFilesDir() 또는 getExternalCacheDir()의 리턴값으로 나오는 디렉토리에 파일을 저장하면 된다. 탑 레벨 디렉토리에 파일을 저장하지 않도록 주의한다.
Context.getExternalFilesDir()
앱 내부에서만 사용될 private 디렉토리의 절대경로를 리턴한다.
이 메소드로 리턴되는 외장 메모리 공간은 앱 내에서 private하게 저장되어야 할 파일들이 저장되는 공간이다. 이곳에 저장된 파일들은 앱이 삭제되면 같이 사라지게 된다.
반면에, Context.getExternalStoragePublicDirectory(String) 메소드로 리턴되는 외장 메모리 공간에는 앱들끼리 공유되어야 할 파일들이 위치하는 공간이다. 물론, 앱 하나가 삭제된다고 해서 이 곳에 있는 파일이 같이 삭제되지는 않는다.
앱 안에서만 사용할 파일들은 매니페스트 파일에 어떠한 권한도 요청하지 않아도 된다. 하지만, 공유 디렉토리에 파일을 저장해야 하는 앱이라면, AndroidManifest.xml에 다음과 같이 권한을 요청해야 한다.
1 2 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | cs |
write권한만 갖고 있어도 read권한은 자동으로 부여되는것이므로 사실상 첫번째 줄만 있어도 외장 공유 디렉토리에 read/write가 가능하다.
다시 한번 정리하자.
Context.getExternalFilesDirs(String)
Context.getExternalCacheDirs()
Context.getExternalMediaDirs()
3개의 메소드로 얻을 수 있는 공간은 앱 내부에서만 사용할 수 있는 Private한 내부 디렉토리이다. 따라서, 내가 개발하고자 하는 앱이 공유 디렉토리가 아닌 내 앱에서만 사용할 private한 파일을 저장할 필요가 있다면 굳이 Manifest파일에 위와 같이 권한을 요청하지 않고 위의 3가지 메소드로 디렉토리에 접근해서 파일을 저장/삭제등을 하면 된다.
하지만, 대부분의 앱은 앱끼리 파일을 공유해야 하는일이 빈번하게 발생할 수 있다.
이러한 앱들에서는
Context.getExternalFilesDirs()로 얻은 내부 디렉토리는 외부 앱에서 접근이 불가능 하기 때문에 공유 디렉토리에 나의 파일을 저장해야 한다. 물론 공유 디렉토리는 외장 메모리에 저장된다. 외장 메모리 속에 공유 디렉토리가 존재하는것이다.
이 외장 메모리의 공유 디렉토리(getExternalStoragePublicDirectory()의 리턴값)에 파일을 read/write하고자 할때는 매니페스트 파일에 권한을 설정해야 하며, 버전은 킷캣 이상이어야 한다고 한다.(Build.VERSION_CODES.KITKAT)
getExternalStoragePublicDirectory()
이 메소드로 얻을 수있는 외장 메모리 공간은 public한 공간이다. 이 public 디렉토리에는 모든 앱들이 이곳에 파일을 저장할 수 있다. 그렇기 때문에 내가 이곳에 파일을 저장할때는 조심해야 한다. 다른 앱이 저장한 파일을 수정/삭제 하지 않게끔 말이다.
/storage/emulated/0/
이 밑 부분이 공유 폴더이다.
/storage/emulated/0/Android/data/com.codevoila.androidtutorial/
이 디렉토리 하위 부분이 앱의 내부 디렉토리 이다.
출처
https://www.codevoila.com/post/46/android-tutorial-android-external-storage 중요
https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
'컴퓨터 공학과 졸업 > 안드 개발 기록' 카테고리의 다른 글
싱글터치 멀티 터치 MotionEvent (0) | 2018.07.25 |
---|---|
Canvas.save() Canvas.restore() (1) | 2018.07.25 |
어플리케이션 간 파일 공유 2 (0) | 2018.07.22 |
어플리케이션 간 파일 공유 (0) | 2018.07.22 |
MediaStore (0) | 2018.07.21 |
- Total
- Today
- Yesterday
- Polyfill
- rendering scope
- props
- mobx
- server side rendering
- reducer
- webpack
- Action
- reflow
- atomic design
- computed
- design system
- reactdom
- await
- useRef
- state
- es6
- Next.js
- javascript
- react hooks
- hydrate
- react
- async
- useEffect
- Babel
- return type
- type alias
- storybook
- typescript
- promise
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |