1 / 54

자료 관리

10. 자료 관리. 학습목표 프로그램이 생성한 데이터를 영구적으로 저장하는 기술에 대하여 학습한다 . CP 를 통해 다른 응용 프로그램과 정보를 공유하는 방법에 대하여 학습한다 . 내용 파일 입출력 프레프런스 SQLite CP (Content Provider). 1. 파일 입출력. 파일 관리 메서드 안드로이드 자체에는 파일 관리 기능이 따로 포함되어 있지 않다 . 파일 시스템은 기반 운영체제인 리눅스의 것 그대로 사용하며 , 파일 입출력 라이브러리는 자바의 것을 이용한다 .

camden
Download Presentation

자료 관리

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 10 자료 관리

  2. 학습목표 • 프로그램이 생성한 데이터를 영구적으로 저장하는 기술에 대하여 학습한다. • CP를 통해 다른 응용 프로그램과 정보를 공유하는 방법에 대하여 학습한다. • 내용 • 파일 입출력 • 프레프런스 • SQLite • CP (Content Provider)

  3. 1. 파일 입출력 • 파일 관리 메서드 • 안드로이드 자체에는 파일 관리 기능이 따로 포함되어 있지 않다. • 파일 시스템은 기반 운영체제인 리눅스의 것 그대로 사용하며, 파일 입출력 라이브러리는 자바의 것을 이용한다. • 따라서 리눅스 파일 시스템의 이해가 선행되며, 자바 입출력 스트림을 자유자재로 사용할 수 있어야 한다. • 또한, 보안상의 제약으로 인해 Context 클래스에서 보안이 적용된 파일 관리 메서드를 별도로 제공하며, 이를 이용하여 파일을 Open한다. • Context클래스 파일 입출력 메서드 • FileOutputStreamopenFileOutput (String name, int mode) • FileInputStreamopenFileInput (String name) • 각각 쓰기용, 읽기용으로 파일을 열어 스트림을 리턴한다. • name • - 열고자 하는 파일의 이름. • - 파일의 위치는/data/data/패키지명/file디렉토리로지정되어 있으며, 반드시 파일명만 적어야 한다. (임의 경로의 파일을 마음대로 열 수 없으며, 자신의 디렉토리만 액세스 가능하다.) • - 파일명에 경로를 표시하는 ‘/’문자가 들어가면 에러 처리된다.

  4. 1. 파일 입출력 • 파일 Open 시 스트림이 리턴되며 이후부터 자바의 스트림 입출력 메서드를 이용한다. • 파일 삭제 및 파일 List 구하기 메서드 • mode • - 파일 생성시 아래의 mode중 하나를 지정한다. • booleandeleteFile (String name) • String[] fileList () • 둘 다 패키지 디렉토리 아래의 파일들만 관리할 수 있으며, 경로는 사용할 수 없다 .

  5. 1. 파일 입출력 • FileIO예제 • 레이아웃은 버튼 4개와 입출력 결과 확인을 위한 에디트를 하나 배치한다. • 각 버튼 클릭 시 파일 입출력 동작 수행한다.

  6. 1. 파일 입출력 • Save버튼 - 쓰기용, 공유 모드로 test.txt파일을 생성한다. - 리턴된 출력 스트림의 입출력 메서드로 데이터 출력 시 파일에 기록된다. -write메서드로 문자열 데이터를 출력, close메서드로 스트림을 닫는다. - 파일 입출력 중 예외가 발생할 확률이 높으므로 try, catch를 이용하여 예외 처리를 해야 한다. - 파일을 기록 후 에디트에 기록 완료 사실을 출력한다. ※ 스트림은 가비지 컬렉터의 정리 대상이 아니므로 다 사용한 후 반드시 닫아야 하며, 예외 발생 시 스트림을 닫기 위해 finally블록에서 close를 호출하는 것이 정석이다. [ FileIO 예제 실행 결과 ] • Load버튼 • - 파일 생성 여부를 확인할 수 있다. • - test.txt 파일의 문자열을 읽어 아래쪽의 에디트에 출력한다. • -openFileInput메서드로 스트림을 열고, read메서드를 이용하여 읽는다. • - 파일이 없으면 FileNotFoundException예외가 발생한다. ( 이 예외는 흔히 발생하므로 반드시 예외처리를 해야한다. ) • 문자열 외에 이미지나 복잡한 설정 정보 등 큰 이진 데이터도 저장 가능하며, 사용자가 삭제하지 않는 한은 영구적으로 보존되며 읽고 갱신 가능하다.

  7. 1. 파일 입출력 • LoadRes버튼 - 응용 프로그램 동작에 필요한 대용량의 읽기 전용 데이터 파일은 리소스에 포함시켜 두는 것이 좋다. ( ex: 게임의 지도 맵 데이터, 우편 번호부, 영한사전 데이터 등 ) - 분리된 파일로 배포 가능하지만 파일이 누락되면 이상 동작할 위험이 있고 불의의 사고로 파일이 변경될 가능성도 배제할 수 없으며, 리소스에 파일을 넣어두면 실행 파일에 포함되므로 편리하고 안전하다. - 포함시킬 파일은 res폴더 아래에 raw폴더를 생성하고 복사해 둔다. - 리소스의 파일을 읽을 때는 Resources객체의 메서드를 사용하며, id로는 확장자를 뺀 파일명을 부여한다. • InputStreamopenRawResource (int id) • - 입력 스트림이 리턴되며이후부터는 자바의 표준 스트림 메서드로 액세스한다. • - 예제에서는 텍스트파일을 넣어두었으므로 read메서드로 읽어 문자열로 바꾼 후 에디트에 출력한다. • - res/raw폴더에 저장되는 파일은 원래 모습 그대로 저장되며, 어떠한 변형도 가해지지 않는다. • - res/xml폴더에 저장되는 파일은 이진 형태로 컴파일되어 포함된다. • Delete버튼 • - 생성된 test.txt파일을 삭제하며, deleteFile메서드로 파일 이름만 전달하면 삭제된다. • - 패키지 폴더 아래의 파일만 삭제 가능하므로 결국 자신이 만든 파일만 삭제할 수 있다. • - 파일이 없으면 삭제 에러 처리된다.

  8. 1. 파일 입출력 • 파일 공유 • 모바일 사용자는 비전문가들이므로 임의의 파일을 자유롭게 건드릴 수 있도록 관리해서는 안된다. • 따라서, 안드로이드 폰 및 에뮬레이터에는 파일 탐색기가 제공되지 않으며, 이미지 뷰어, 동영상 재생기, MP3플레이어 등으로 데이터 파일만 볼 수 있도록 되어있다. • 안전상의 이유로 최종 사용자는 장비의 파일 시스템을 액세스하지 못하도록 금지되어 있으며, 개발자들은 이클립스의 DDMS를 사용하여 File Explorer탭에서 장비나 에뮬레이터의 파일을 관리한다. • FileIO예제 디렉토리 • /data/data/exam.Data/files아래에 test.txt파일이 생성되어 있다. • 탐색기 상단의 버튼을 사용하여 파일을 가져오거나 복사 또는삭제가 가능하다. • adb의 push, pull명령으로 파일 관리가 가능하지만 DDMS가 더 편리하다. [ eclipse의 DDMS- File Explorer탭 ]

  9. 1. 파일 입출력 • 파일은 기본적으로 생성한 프로그램만 액세스할 수 있으며, 다른 응용 프로그램이 파일을 공유하려면 여러 가지 조건을 만족해야 한다. • 대상 파일의 액세스 모드가 외부에 대해 허용되어 있어야 한다. • FileIO예제 test.txt파일의 퍼미션란을 보면 -rw-rw-r--로 되어 있으며, 이는 파일 생성 시 MODE_WORLD_READABLE플래그를 주었기 때문이다. • 외부의 파일을 읽으려면 해당 파일을 생성한 프로그램의 컨텍스트를 구해야 한다. • 파일 열기 메서드에 경로를 지정할 수 없으므로 해당 프로그램의 컨텍스트를 구해야 한다. • 외부 프로그램의 컨텍스트를 구할때는 아래의 메서드를 호출한다. • Context createPackagecontext (String packageName, int flags) • - packageName인수 : 패키지 경로 지정 • - flage : 모드를 지정하며, CONTEXT_IGNORE_SECURITY플래그 지정. (디폴트 모드로 열면 보안상의 이유로 예외가 발생한다.) • ※ 이 메서드를 호출하려면 대상 프로그램의 패키지 경로를 정확히 알고 있어야 하며, 해당 패키지가 설치되어 있어야 한다. • 컨텍스트를 구한 뒤 컨텍스트의 파일 열기 메서드로 원하는 파일을 열 수 있다.

  10. 1. 파일 입출력 • ShareFile예제 • 예제는 exam.Data패키지의 컨텍스트를 구하며, Load버튼을 누르면 외부 패키지의 파일을 열어 그 내용을 아래쪽 에디트에 출력한다. • 컨텍스트를 구한 뒤 컨텍스트의 openFile*메서드를 호출하여 해당 컨텍스트가 생성한 파일을 열 수 있다. • 스트림을 연 뒤에는 자바 문법으로 액세스할 수 있다. [ ShareFile 예제 실행 결과 ] • ※외부의 파일을 읽을 때는 여러 가지 예외가 발생할 수 있으므로 적절한 예외 처리가 필요하다. • ※이 방법을 이용한 응용 프로그램끼리의 파일 공유는 권장되지 않으며, 추후 좀 더 일반적인 방법들이 제공되므로 이 방법은 가급적 사용하지 않는 것이 좋다.

  11. 1. 파일 입출력 • SD카드 • 안드로이드의 파일 시스템은 운영체제에 의해 보호되어 있으나, MP3, 비디오 파일, 그림 파일 등 공동으로 사용될 필요가 있는 단순 데이터는 보안이 중요하지 않다. • SD카드는 보안과 무관한 단순 데이터 파일 저장을 위해 사용되며, 대용량 멀티미디어 파일 저장에 적합하다. • SD카드는 운영체제와 분리된 기억장치이며 FAT포맷으로 되어 있어 보안상의 제약 없이 누구나 사용 가능하다. • SD카드 액세스를 위해선 SD카드가 필요하며, 에뮬레이터를 이용한 실습을 위해 mksdcard로 생성하거나 AVD생성 시 SD카드 용량을 지정하여 생성할 수 있다. • AVD생성 시 SD카드 용량 지정 - SD Card의 Size로 지정한 용량만큼 AVD디렉토리에 sdcard.img파일이 생성되며 이 파일이 가상의 SD카드로 활용된다. [ AVD - SD Card 용량 지정]

  12. 1. 파일 입출력 • mksdcard.exe유틸리티를 이용한 가상 SD Card 생성 • mksdcard [ -l 레이블 ] 용량 파일명 • - AVD와 별도로 SD카드를 생성하며, 필요한 만큼의 SD카드 생성이 가능하다. • - 용량과 파일명을 지정하면 지정한 용량대로 하드 디스크에 파일이 생성된다. (ISO파일과 비슷한 개념) • - 임의로 이름 설정이 가능하며 생성 후 삭제, 복사, 이름 변경이 자유롭다. • - 용량은 자유롭되 최소 8M이상이어야 한다. • - 명령창의 tools디렉토리에서 아래의 명령을 입력한다. [ mksdcard 생성된 SD카드 경로 지정] • mksdcard 16M testcard.sd • - 16M크기의 파일이 포맷된 상태로 생성된다. • - 생성된 SD카드를 사용하려면 AVD생성 시 File에서 SD카드 파일의 경로를 지정한다. • - 에뮬레이터가 열릴 때마다 지정한 SD카드를 로드한다. • - 특정 프로젝트에 특정 SD카드를 사용하려면 프로젝트 구성의 Target페이지에서 명령행 옵션에 아래와 같이 지정하며, 이 옵션을 적용하려면 에뮬레이터를 재시작하여야 한다. • - sdcard c:\testcard.sd

  13. 1. 파일 입출력 • 아래의 Environment클래스 정적 메서드를 호출하여 현재장비에SD카드 장착 여부와장착되어 있을 때 그 경로를 확인한다. • Static String getExternalStorageState () • Static File getExternalStorageDirectory () • Static File getRootDirectory () • Static File getDataDirectory () • Static File getDownloadCacheDirectory () • getExternalStorageState • - 외부 저장 장치, 즉 SD카드의 현재 상태를 조사한다. • - 장착되어 있으며 읽고 쓰기가 가능한 상태이면 MEDIA_MOUNTED가 리턴되며 그렇지 않을 시엔 MEDIA_UNMOUNTED가 리턴된다. • getExternalStorageDirectory • - SD카드가 마운트된 경로를 조사한다. • - SD카드는 통상 리눅스 파일 시스템의 /sdcard 경로로 마운팅된다. • 나머지 메서드는 루트, 데이터, 캐쉬 경로를 조사한다. • SD 카드의 파일을 액세스하려면 매니페스트에 아래의 퍼미션을 지정해야 한다. • <uses-permission android:name=“android.permission.WRITE_EXTERNAL_STORAGE”/> • 퍼미션이 지정되어 있지 않으면 컴파일은 되지만 모든 액세스가 실패로 처리된다. • SD카드 마운트 및 경로 조사 후엔 표준 자바 입출력 클래스로 파일과 디렉토리들을 액세스 및 관리할 수 있으며, 별다른 제약은 없다.

  14. 1. 파일 입출력 • SDCard예제 • SD카드의 현재 상태를 조사하고 SD카드에 파일을 생성 및 읽는 예제이며, 레이아웃은 버튼 세 개와 결과 확인을 위한 에디트를 배치한다.

  15. 1. 파일 입출력 • 파일 입출력을 위해 경로를 알아야 하므로 onCreate에서 SD카드의 장착 여부와 경로를 미리 조사해 둔다. • Test버튼 - 그 외 나머지 디렉토리 정보를 조사하여 아래쪽 에디트에 출력한다. - 실습 환경에서 아래의 그림과 같이 출력되면 정상적으로 마운트되어 있는 것이다. • Load, Save버튼 • - 자유로운 파일 관리를 위해 디렉토리를 생성하고 그 안에파일을 생성한다. • - 생성된 파일은 DDMS의 파일 탐색기로 확인 가능하다. • - Load버튼을 누르면 아래쪽 에디트에 파일의 내용이 출력된다. • - 자바를 사용하여 예제의 File클래스와 입출력 스트림을 작성한다. [ SDCard 예제 실행 결과 ]

  16. 1. 파일 입출력 • TextLog • 이클립스에서 디버깅을 지원하며 안드로이도 시스템 차원에서 로그 기능을 제공한다. • 단계 실행은 멀티 스레드 디버깅이나 비순차적 실행에는 취약하여 이벤트 발생 순서를 정확하게 알기 어려우며, 시스템 로그는 호스트에 장비가 장착되어 있어야 사용 가능하지만 실무 개발 시엔 그렇지 못한 경우가 많다. • 하드웨어와 소프트웨어가 동시에 개발될 때는 디바이스 드라이버가 완비되지 못해 장비를 개발 컴퓨터에 붙이지 못하는 경우가 흔하며, 이때 전체 이미지를 ROM에 구워서 테스트해야 하므로 시스템 로그 기능을 사용하지 못한다. • 시스템 로그는 장비가 다운되었을 시 이전의 사건들은 확인이 불가능하다. ※개발툴의 지원이 불가능할 때 디버깅 방법은 텍스트로 로그를 남기는 방법밖에 없으며, 외부 지원이 없으므로 응용 프로그램이 스스로 로그를 남기고 이를 확인해야 한다.

  17. 1. 파일 입출력 • TextLog예제

  18. 1. 파일 입출력 • TextLog예제

  19. 1. 파일 입출력 • TextLog클래스 - 응용프로그램 폴더, SD카드, 시스템 로그에 3중으로 로그를 기록할 수 있다. - mDir멤버 : 로그를 남길 위치 지정. (디폴트는 자기 폴더 및 SD카드) - mFile : 로그 파일명. andlog.txt로 초기화되며 태그값은 mTag로 지정. - mFile, mTag mDir 멤버는 별도의 액세스 메서드가 없는 대신 공개되어 있으므로 필요 시 외부에서 값을 직접 수정할 수 있다. • init메서드 - 로그를남길 준비. 장비에 SD카드 장착 여부, 경로를 조사한다. - SD카드가 없으면 자신의 디렉토리에만 기록되며, 로그 기록 시작과 현재 시간으로 첫 번째 로그를 남긴다. - 로그를 남기는 주체인 Context를 받아놓는데 이 값이 있어야 파일 생성이 가능하다. • reset메서드 - 작성된로그를 모두 삭제하며 리셋되었다는 기록을 남긴다. • o메서드 - 로그를 기록하며 자주 호출되므로 메서드 이름을 짧게 지정하였다. - 인수로 문자열 하나만 전달받으며 +로 연결하면 변수값도 사용할 수 있다. - 로그 출력문 : mFile경로의 파일을 추가용으로 open, 로그 문자열과 개행 문자열을 뒤에 덧붙이고 파일 close. - SD카드에 대한 기록문도 로그 출력문과 거의 동일하며 시스템 로그 기록문은 Log.d호출로 되어있다.

  20. 1. 파일 입출력 • ViewLog메서드 - 작성된로그를 대화상자로 나타내며, 로그 파일 전체를 읽어 문자열로 만든 후 출력한다. - AlertDialog는 내용이 많을 경우 스크롤을 지원한다. • addMenu, execMenu메서드 - 로그 확인, 리셋을 위한 명령을 호스트의 메뉴에 덧붙이고 실행한다. ※외부에서 ViewLog, reset메서드를 직접 호출할 수 있지만 적당한 시점이 없는 경우엔 메뉴를 사용하는 것이 편리하며, 이 두 메서드는 호스트를 대신하여 메뉴를 관리한다. • lg클래스 - TextLog의 o메서드를 대신 호출한다. - public이 아니므로 같은 패키지 내부에서만 사용 가능하며 외부 패키지에서 호출 시 사용할 수 없다. - 외부 패키지에서 호출 시 TextLog클래스를 import하여 사용한다.

  21. 1. 파일 입출력 • TextLogTest예제 • onCreate에서 init메서드를 호출하여 초기화하고 메뉴 생성 및 실행시에 addMenu, execMenu메서드를 호출한다. • 기록을 남길 부분에서 lg.o메서드로 문자열 형태의 기록을 남긴다. • 프로그램이 실행 중에 다운되어도 reset 명령을 내래지 않는 한 로그는 그대로 남아있으며, 장비를 재부팅해도 로그 파일은 항상 유지된다. [ TextLogTest 예제 실행 결과 ]

  22. 2. 프레프런스 • 프레프런스 • 프레프런스는 응용 프로그램의 설정 정보를 영구적으로 저장하는 장치이며, 사용자의 옵션 선택 사항이나 프로그램 자체의 구성 정보를 주로 저장한다. • 윈도우 환경의 레지스트리나 리눅스 환경의 세팅 파일 정도에 대응되는 개념이되, XML포맷의 텍스트 파일에 정보를 저장하므로 세팅 파일이나 INI파일에 더 가깝다. • SharedPreferences클래스 • 프레프런스의 데이터를 관리하는 클래스이다. • 응용 프로그램내의 모든 액티비티가 공유하며, 한쪽 액티비티에서 수정 시 다른 액티비티에서도 수정된 값을 읽을 수 있다. • 응용 프로그램의 고유한 정보이므로 외부에서는 읽을 수 없다. • 컨텍스트의 아래 메서드로 생성한다. • SharedPreferencesgetSharedPreferences (String name, int mode) • - 첫번째 인수 : 프레프런스를 저장한 XML파일의 이름이다. • - 두 번째 인수 : 파일의 공유 모드로 0이면 읽기 쓰기가 가능하고, MODE_WORLD_READABLE은 읽기 공유, MODE_WORLD_WRITEABLE는 쓰기 공유이다. • 액티비티의 메서드로도 프레프런스를 열 수 있으나 생성한 액티비티 전용이므로 같은 패키지의 다른 액티비티는 읽을 수 없다.(파일명인수 생략 시 액티비티와 동일한 이름의 XML파일 생성) • public getSharedPreferences (int mode)

  23. 2. 프레프런스 • 프레프런스는 키와 값의 쌍으로 데이터를 저장한다. • 키는 정보의 이름이며 값은 정보의 실제값이다. • 여러 타입의 정보를 저장할 수 있으며 가장 자주 사용되는 타입은 정수, 문자열 논리형으로 아래의 메서드를 이용하여 읽을 수 있다. • int getInt (String key, intdefValue) • String getString (String key, String defValue) • boolean getBoolean (String key, booleandefValue) • - 읽는 데이터 타입이 다를 뿐이며 사용 방법은 동일하다. • - key인수 : 데이터의 이름 지정 • - defValue인수 : 값이 없을 때 적용할 디폴트 지정. • ※최초 실행될 때에는 프레프런스가 생성되기 전이므로 디폴트가 리턴되므로 여기서 지정한 디폴트가 곧 프로그램 설정의 초기값이 된다.

  24. 2. 프레프런스 • 프레프런스 클래스 자체에는 값을 읽는 메서드만 제공되며 값을 기록하는 메서드는 이너 클래스인 SharedPreferences.Editor가 제공한다. • 값을 읽는 것에 비해 변경할 때는 동기화를 해야 하며 Editor는 모든 변경을 모아 두었다가 한꺼번에 적용하는 기능을 제공한다. • 데이터 저장 시 프레프런스의 edit메서드를 호출하여 Editor객체를 먼저 얻어야 하며, Editor객체에는 값을 저장하고 관리하는 메서드가 제공된다. • SharedPreferences.EditorputInt(String key, int value) • SharedPreferences.EditorputBoolean(String key, int value) • SharedPreferences.EditorputString(String key, String value) • SharedPreferences.Editor remove(String key) • Boolean commit() • SharedPreferences.Editor clear() • - 저장하는 데이터 타입에 따라 각각의 기록 메서드가 제공된다. • - put*메서드로 값을 저장한 후에 반드시 commit메서드를 호출해야 실제 파일에 저장된다. • - 만약 두 개의 스레드가 동시에 프레프런스를 편집할 시 먼저 적용한 내용은 나중에 적용한 내용에 덮힌다. • - commit메서드는 변경 사항을 원자적으로 적용하므로 섞이지 않는다.

  25. 2. 프레프런스 • PrefTest예제 • 문자열과 정수열을 저장하는 예제 • 문자열, 정수를 입력 받기 위해 두 개의 에디트를 배치한다. • 에디트를 이용하여 사용자는 문자열 입력 및 편집을 실행할 수 있으나, 저장을 하지 않으므로 종료 후 재실행 시 초기화된다. • 세션간 정보 유지를 위해선 정보의 저장이 필요하며, 정보 저장을 위한 최적의 장소는 프레프런스이다. [ preftest 예제 실행 결과 ]

  26. 2. 프레프런스 • PrefTest예제 • onPause로프레프런스에 데이터를 저장하며, 액티비티가 종료되기 전에 반드시 거치게 되어있다. • 프레프런스 객체 얻기 - getSharedPreferences메서드를 이용하여, PrefTest프레프런스를 open 한다. - 파일명이 액티비티명과 같을땐 아래의 방법으로 호출 가능하다. • SharedPreferencespref = getPreferences(0); • Editor객체 얻기 • - 프레프런스에 정보를 기록하기 위해 edit메서드를 이용한다. • - 사용자가 에디트에 입력한 정보를 먼저 읽는다. • - 문자열 타입 : getText().toString() • - 정수 타입은 문자열을 정수로 변환하여 읽으며, 예외처리한다. • 프레프런스로 정보 출력 • - 이름(Name): putString() • - 학번(StNum): putInt() • - 저장 후 commit메서드 호출 • ※ 메모리가 부족하면 onStop, onDestroy 는 호출되지 않을수도 있으므로 반드시 onPause에서 저장해야 한다.

  27. 2. 프레프런스 • PreferenceActivity • 프로그램은동작이 고정적이지 않으므로 어느 정도의 옵션을 소유한다. • 옵션은 사용자의 취향에 따라 프로그램의 기능을 선택적으로 사용할 수 있도록 함으로써 다양한 사용자의 기호를 충족시키는 역할을 한다. • 프로그램이 옵션을 제공하기 위해 사용자가 실행 중 옵션을 편집할 수 있는 UI를 제공해야 하며 사용자의 선택을 프레프런스에 저장하고 다시 읽어오는 기능이 필요하다. • 안드로이드에서 옵션들을 입력 받고 관리하는 자동화된 방법이 제공된다. • PreferenceActivity로부터 상속 받고 입력 받고자 하는 옵션의 종류를 XML문서에 기록한다. • 액티비티의 레이아웃 루트는 반드시 PreferencesScreen이어야 하며, 옵션 타입에 따라 위젯을 배치하면 남은 처리는 자동으로 수행된다.

  28. 2. 프레프런스 • PrefActivity예제 • 나이와 성별을 입력 받기 위한 에디트와 체크 박스를 배치한다. • 위젯이 프레프런스 입출력 기능을 가지므로 key속성에 저장할 키의 이름과 defaultValue속성에 처음 적용할 값을 지정해야 한다. • summary속성에 옵션에 대한 간단한 안내 문자열을 작성한다. • PreferencesActivity로부터 상속받아 액티비티를 생성, 초기화 시에 onCreate메서드에서 addPreferencesFromResource메서드로 레이아웃을 지정한다. • 액티비티가 열릴 때 옵션값이 위젯으로 로드되고 닫히기 전에 옵션값을 다시 저장한다. [ PrefActivity 예제 실행 결과 ]

  29. 3. SQLite • 도우미 클래스 • 조직화된 대량의 데이터를 효율적으로 관리하기 위해 데이터베이스가 필요하다. • 안드로이드는 운영체제 차원에서 SQLite라이브러리를 포함하고 있으며, 별도의 설정 없이 DB를 사용할 수 있다. • SQLite • 2000년 리처드 힙(Richard Hipp) 박사에 의해 개발된 무료 DB엔진. • 안정적, 적은 용량, C 언어로 작성되어 속도가 빠르며 소규모의 데이터베이스에 적합. • 아이폰, 심비안 등의 모바일 환경, 휴대용 MP3등에서 주로 이용됨. • 데이터를 저장하는 장소는 단순한 파일이므로 별도의 서버 및 연결, 권한 설정 등이 필요 없다. • 복사, 삭제, 이동이 가능하며 설정 및 관리 정책은 불필요하다. • 복수 사용자는 지원되지 않는다. • 안드로이드의 일부로 포함되어 별도의 라이브러리가 필요하지 않다. • SQLite정보 : www.sqlite.ort ※이용을 위해 데이터베이스에 대한 기본 개념과 표준 SQL구문에 대한 선행 학습이 필요하다.( 쿼리를 대신하는 메서드를 제공해 주지만 SQL만큼의 융통성이 부족하다.)

  30. 3. SQLite • 정보를 저장할 DB를 생성하고 관리할 정보와 업무 규칙에 적합한 테이블을 디자인한다. • SQLite는 초기화와 테이블 디자인을 위한 별도의 툴을 제공하지 않으므로 초기화 역시 SQL스크립트로 처리해야 한다. • SQLiteOpenHelper클래스 • 안드로이드에서 제공하는 도우미 클래스로 DB생성 및 Open 처리를 담당한다. • 추상 클래스이므로 서브 클래스를 파생하여 사용하는 DB의 구조에 맞게 메서드를 재정의, 적절한 스크립트를 작성해야 한다. • 생성자 - context: DB를 생성하는 컨텍스트, 보통 메인 액티비티를 전달. - name, version : DB파일의 이름 및 버전, 이후 DB 생성 및 업데이트 시 이용됨. - factory : 커스텀 커서 사용을 위해 지정, 표준 커서 이용 시 null로 지정. • 객체를 생성해 놓으면 DB가 필요한 시점에 아래의 메서드가 호출된다. • - onCreate : CREATE TABLE 문을 실행하여 테이블을 생성. • - onUpgrade : DB의 버전이 변경될 때 호출됨.

  31. 3. SQLite • 생성 및 업그레이드를 위한 메서드 정의 후 DB필요 시 아래의 메서드를 호출한다. • - getReadable(Writable)Database메서드만 호출하면 이후는 자동 처리된다. • - DB파일이 없으면 파일 생성 후 onCreate를 호출하여 테이블을 생성한다. • - 버전 변경 시 onUpgrade를 호출하여 테이블을 수정한다. • - 후에SQLiteDatabase객체가 리턴된다. • EnglishWord예제 • 영한 사전으로 영어 단어와 한글 해석을 필드로 가지는 일종의 맵이다. • 레이아웃은 쿼리 실행을 위한 버튼 4개와 결과 확인을 위한 에디트가 배치된다. • 4개의 버튼을 차례로 누르면 테이블에 레코드가 삽입, 삭제, 갱신되며 현재 레코드 목록을 아래쪽 에디트에 출력한다. [ EnglishWord 예제 실행 결과 ]

  32. 3. SQLite • EnglishWord예제

  33. 3. SQLite • EnglishWord예제 • 메인 액티비티에 4개의 버튼에 대한 클릭 핸들러가 작성되어 있으며 아래족에는 도우미 클래스가 작성되어 있다. • EngWord.db파일 - 예제 실행 후 생성된 DB파일이며,DDMS로 패키지 디렉토리를 살펴보면 database디렉토리가 생성되어 있으며 이 안에 있다. - 단순 파일이므로 복사, 이동, 삭제가 가능하다. • WordDBHelper클래스 - 도우미 클래스를 상속받아 정의된 클래스이며, 처음 정의한 것이므로 버전은 1이다. - onCreate, onUpgrade메서드를 호출한다. • onCreate - execSQL메서드로 CREATE TABLE 명령을 실행하여 dic테이블을 생성한다. - _id 필드 : PK로 사용. 차후 CP로 확장하거나 커서 어댑터와 연결을 위해 필요하다. - eng : 영어 단어 저장 - han : 한글 해석 저장 • ※ 일반적인 테이블 설계 지침상 PK는 레코드를 효율적으로 관리하기 위해 필수적이므로 가급적이면 _id 필드는 포함시키는 것이 좋다.

  34. 3. SQLite • onOpen - DB가 존재할 때 호출되며, 생성자로 전달된 DB를 열기만 하므로 재정의할 필요는 없다. • onUpgrade - 테이블 삭제 후 동일한 테이블을 재생성하여 업그레이드하는 흉내만 낸다. - 실제로는 변경된 구조의 테이블을 재생성하거나 ALTER TABLE문으로 변경된 스키마에 맞게 테이블의 구조만 수정해야 한다. • 액티비티는 WordDBHelper타입의 mHelper멤버를 미리 생성해 두며 이후 DBopen 메서드 호출 시 DB의 존재 여부와버전을 비교하여 DB를 생성, 업그레이드하거나 기존의 존재하는 DB를 오픈한다. • DB관리 업무는 도우미가 담당하므로 필요 시 DB를 오픈하여 사용하면 된다. • 도우미를 사용하지 않고 직접 DB생성 시엔 아래의 메서드를 사용한다. • SQLiteDatabaseContext.openOrCreateDatabase (String name, int mode, SQLiteDatabase.CursorFactory factory) • - 메서드를 사용하여 DB파일을 생성하고 리턴되는 db의 execSQL메서드를 통해 CREATE TABLE을 실행하면DB를 만들 수 있다. • - DB가 없는 경우, 이미 만들어진 경우, 버전이 변경된 경우 등을 사용자가 직접 판단해야 한다. • ※도우미는 개발자가 작성한 스크립트를 언제 어떤 조건에서 호출할 것인가를 대신 판단해 준다.

  35. 3. SQLite • 쿼리 실행 • 새 레코드 삽입 • DB에 기록하기 위해 getWritableDatabase메서드로 DB를 오픈하면 기록 가능한 DB객체가 리턴된다. - onCreate메서드를 호출하여 DB생성또는 onOpen메서드를 호출하여 기존의 DB open • DB파일의 존재 유무, 버전 비교 등을 종합적으로 판단, 어떤식으로 DB객체를 생성할 것인지는 도우미가 판단한다. - onCreate, onUpgrade 등의 메서드에 해당 동작 명령을 채워야 한다. • 이후 도우미가 리턴한 DB객체의 메서드를 호출하여 레코드를 관리한다. • ContentValues클래스 • 테이블에 삽입되는 레코드를 표현하며, 레코드 하나는 임의의 타입을 가지는 필드들의 집합이므로 테이블마다 형태가 다르다. • 빈 객체를 만든 후 put메서드를 호출하여 필드와 값의 쌍을 여러 개 저장한다. • 모든 기본 타입에 대해 오버로딩되어 있으므로 필드의 타입에 맞는 메서드를 호출한다. • void put (String key, Integer value) • void put (String key, String value) • void put (String key, Boolean value) • - ContentValues는 레코드에 포함된 필드의 이름과 값의 맵이고레코드에 포함되는 컬럼의 개수나 타입이 가변적이므로 맵 형태로 이름과 값의 배열을 전달받는다. • - _id 필드는 자동으로 증가되는 값이므로 별도로 값을 지정하지 않아도 된다.

  36. 3. SQLite • 삽입할 레코드가 준비되면 아래의 메서드로 삽입한다. • long SQLiteDatabase.insert (String table, String nullColumnhack, ContentValues values) • - 테이블 이름과 삽입할 레코드를 인수로 전달한다. • 별도의 삽입 메서드를 쓰는 대신 아래의 메서드로 SQL명령을 직접 실행 가능하다. • void execSQL (String sql) • - 이 메서드는 SELECT명령을 제외한 대부분의 명령을 직접 실행할 수 있다. • - 인수로 SQL문자열 하나만 전달되며, 이 문자열 안에 대상 테이블 이름과 삽입할 레코드의 필드값이 모두 기록된다. • - 예제에서는 두 가지 방법 모두 사용하여 레코드를 삽입하였다. • SQLite는 SQL을 잘 모르는 초보자를 위하여 SQL명령의 각 부분을 인수로 받아들이는 메서드도 제공한다. • 레코드를 삭제, 갱신할 때는 아래의 메서드를 사용한다. • int delete (String table, String whereClause, String[] whereArgs) • int update (String table, ContentValues values, String whereClause, String[] whereArgs) • - 삭제할 레코드를 지정하는 where절과 where절 내의 ? 기호를 대체할 문자열, 갱신 대상 필드의 값 등을 인수로 제공한다. • - 갱신 시 ContentValues에 갱신 대상 필드의 값을 지정하고 갱신 대상 행은 where절로 지정한다. • - 예제에서는 메서드 호출문을 사용하되 대응되는 SQL문도 주석으로 묶어 같이 작성하였다.

  37. 3. SQLite • 레코드 검색 메서드 • Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) • 검색 방법이 다양하므로 인수도 많이 필요하다. • 각각 SELECT 문의 WHERE절, ORDER BY 절, GROUP BY 절, HAVING, TOP절, DISTINCT옵션 등에 대응된다. • 모든 조건절을 다 사용하는 경우는 드물며 필요 없는 절에 대해서는 null로 지정한다. • 이 메서드를 사용하는 대신 rawQuery메서드로 SELECT문을 바로 실행 가능하다. • SELECT문은 결과셋을 리턴하기 위해 rawQuery메서드로 실행해야 한다. • 예제에서는 query메서드를 호출하는 것과 SELECT문을 직접 실행하는 두 가지 코드가 모두 작성되어 있다. • ※SQLite가 쿼리 메서드를 제공하는 이유는 SQL초보자에게 편의를 제공하기 위해서이며, 메서드의 인수 의미를 이해하려면 SQL문법을 알아야 한다. • ※쿼리 메서드는 전달받은 인수를 조립하여 SQL명령을 만들며 SQL명령으로 쿼리를 실행한다. • ※데이터베이스 프로그래밍을 위해선 가급적이면 메서드에 의존하는 것보다 범용적인 SQL문을 익힐 것을 권장한다.

  38. 3. SQLite • 쿼리 결과는 결과셋 자체가 리턴되지 않으며 위치를 가리키는 커서로 리턴된다. • 커서는 결과셋의 한 위치를 가리키는 일종의 포인터로 for문의 제어 변수와 유사하다. • 랜덤 액세스를 지원하므로 임의 위치로 이동하여 레코드를 읽을 수 있다. • 커서의 메서드 목록

  39. 3. SQLite • 쿼리를 실행한 후 리턴되는 커서는 결과셋의 첫 레코드 이전을 가리킨다. - 첫 레코드를 읽으려면 moveToNext, moveToFirst메서드를 먼저 호출하여 첫 레코드로 이동해야 한다. - moveToNext가 false를 리턴할 때까지 루프를 돌며 전체 결과셋을 순회한다. • 결과셋은 처음부터 끝까지 순회하며 한번에 다 읽는 것이 보통이므로, 쿼리를 읽는 코드는 통상 while(moveToNext){}의 형태이다. • 루프를 돌며 각 레코드의 컬럼값을 읽는다. • SQLite는 타입 점검을 느슨하게 수행하므로 반드시 컬럼의 타입과 같은 타입으로 읽을 필요는 없다. - 정수형 필드를 읽어 문자열로 출력할 때 getInt로 읽어 문자열로 변환할 필요 없이 getString으로 읽는 것이 편하다. - 예제 테이블의 eng, han은 둘 다 문자열 필드이므로 getString을 이용하여 읽는다. - 필드 번호를 분명히 알고 있을 때는 상수를 바로 사용 가능하지만, 그렇지 않을 시엔 getColumnIndex메서드로 컬럼 번호를 조사한 뒤 값을 읽어야 한다. • 결과셋을 하나의 문자열로 조립하여 에디트에 출력하되 비어 있을 시 빈 결과셋임을 출력한다. • 결과셋을 다 읽은 후 커서와DB는 반드시 닫아야 한다.

  40. 3. SQLite • 커서 바인딩 • 결과셋이 많을 때 쿼리로 전체를 읽어 화면에 출력하면 속도가 매우 느려진다. • 이 경우 커서를 어댑터에 바인딩해 놓고 어댑터가 필요할 때 커서를 이동시켜 현재 꼭 필요한 레코드만 읽어 어댑터 뷰 위젯에 출력한다. • 커서를 사용하는 어댑터의 생성자는 아래와 같다. • SimpleCursorAdapter (Context context, int layout, Cursor c, String[] from, int[] to) • 레코드를 출력할 레이아웃과 데이터 원본인 커서를 전달한다. • 레이아웃에 정보를 출력할 위젯을 배치한 후 열과 위젯을 짝지어준다. • - from : 커서의 열 이름 배열. • - to : 각 열이 출력될 위젯의 ID배열.

  41. 3. SQLite • ProductList예제 • 상품목록을 보여주는 데이터베이스를 생성하는 예제이다. • 도우미 클래스의 구조는 앞 예제와 거의 동일하며, 생성하는 테이블의 개수와 스키마만 다르다. • 레이아웃은 2개의 텍스트를 가지는 표준 레이아웃을 사용하고 name, price 필드를 각각 text1, text2에 연결했다.

  42. 3. SQLite • onCreate - product테이블 생성 - name : 상품의 이름 - price : 가격 정보 • 액티비티는 도우미 객체를 생성한 후 product 테이블의 모든 레코드를 검색하여 커서에 대입한다. • startManagingCursor메서드 - 액티비티의 생명주기에 맞춰 커서를 자동으로 관리하도록 요청한다. • 리스트 뷰에 커서 어댑터를 연결해 놓으면 DB의 내용이 커서로 읽혀저 리스트 뷰의 위젯에 나타난다. • sqlite3유틸리티 • 안드로이드가 제공하는 DB관리 유틸리티로, 이를 사용하면 명령행에서 DB를 직접 조작 가능하다. • 불필요한 레코드 삭제나 삽입한 레코드의 확인 시 편리하다. • adb shell 명령으로 쉘로 들어간 후 sqlite3뒤에 열고자 하는 DB의 절대 경로를 지정한다. [ ProductList 예제 실행 결과 ] [ 가격이 1000원 이상인 제품 출력 결과 ] • ※SQLite는 UTF-8포맷으로 데이터를 저장하므로 한글이 제대로 출력되지 않으며, 명령행의 코드 페이지를 65001로 바꾸고 글꼴을 한글 트루타입 폰트로 맞춰야만 결과를 확인할 수 있다.

  43. 4. CP (Content Provider) • URI (Uniform Resource Identifier) • 안드로이드의 보안 정책상 응용 프로그램이 만든 데이터는 기본적으로 혼자만 액세스 가능하며, 외부로 공개하려면 Content Provider(CP)를제공해야 한다. • CP는 안드로이드응용 프로그램을 구성하는 컴포넌트 중 하나로 데이터를 제공하는 역할을 하며, 응용 프로그램끼리 데이터를 공유하는 유일한 방법이다. • URI • 정보의 위치를 나타내는 고유한 명칭으로 웹상의 주소를 나타내는 URL보다 상위 개념이다. • 누가 어떤 정보를 제공하는지, 어떤 정보를 원하는지에 대한 정보가 작성된다. • 임의의 내용을 가질 수 있는 문자열 형태로, 제공자와 제공받는 자간의 약속이므로 국제표준(RFC2396)에 명시된 방법으로 작성해야 한다. • content://authority/path/id • - content://는 이 문자열이 URI임을 나타내는 접두이며 무조건 붙여야 한다. • - authority : 정보 제공자의 명칭. 중복이 불가능하므로 패키지명을 사용할 것을 권장한다. • - path : 정보의 종류를 지정하는 가상의 경로. 한 제공자가 여러 개의 정보 제공 시 경로를 통해 각 정보를 구분한다. • - id : 구체적으로 어떤 정보를 원하는지 지정. 전체 정보를 모두 읽을 시엔 생략 가능하다.

  44. 4. CP (Content Provider) • CP는 단수와 복수에 대해 두 가지 형태의 URI를 각각 정의해야 한다. • 단수 URI는 복수 URI뒤에 구체적인 정보를 지정하는 id가 추가된다. • URI의 예 – 가상의 회사 stockmarket에서 제공하는 정보 • content://com.stockmarket/stock // 주식 시세 정보 • content://com.stockmarket/fee // 수수료 정보 • content://com.stockmarket/stock/posco // posco 종목의 주식 시세 정보 • content://com.stockmarket/fee/register // 등록 수수료 정보 • - 이 회사는 주식 시세 정보와 수수료 정보를 공개하며 각 정보는 stock, fee라는 경로명으로 구분된다. • - 중복을 피하기 위해com.stockmarket라는 자사의 URI를 사용하였다. • 각 정보는 전체적으로 또는 특정 정보 하나만 참조 가능하다. • 정보 제공자와 정보의 종류에 따라 URI문자열을 만든 후 정적 메서드로 URI객체를 생성한다. • static Uri parse (String uriString) • - 이 메서드는 성능상의 문제로 인해 에러 처리를 하지 않는다. • ※ URI를 잘못 작성하면 예외 발생이 아닌 쓰레기값이 조사되므로 반드시 형식에 맞게 작성해야 한다. • ※ URI의 형식이 틀렸을 때의 동작은 정의되어 있지 않아 아주 위험하므로 충분한 주의를 기울이는 것이 좋다.

  45. 4. CP (Content Provider) • 아래는 URI의 path정보를 문자열 목록으로 조사하는 메서드이다. • List<String> getPathSegments () • - 이 목록의 0번째 요소가 path이며, 1번째 요소가 id이되 /를 제외한 문자열만 조사된다. • - URI로부터 요구하는 정보를 조사할 때 이 메서드를 호출한다. • URI로부터 문자열을 해석하여 정보를 추출하는 것은 번거로우며 문자열 형태이므로 비교 속도 역시 느리다. • UriMatcher유틸리티 클래스 • 문자열안의 요구 정보를 분석하여 정수 코드로 변환한다. • 아래의 메서드로 URI를 미리 분석해 두고 요구 코드를 정의해 둔다. • void addURI (String authority, String path, int code) • int match (Uri uri) • - addURI메서드 : authority, path의 쌍으로 정수 코드와 대응시켜 맵을 등록한다. • - path에서 * 은임의의 문자열과 대응되며, # 은 숫자 하나와 대응된다. • - match메서드 : uri를 분석하여 등록된 정수 코드를 리턴하며, uri에 해당 코드가 없을 시 -1을리턴한다. • CP는 UriMatcher가 분석해 놓은 정수 코드로 요청을 파악하여 정보를 리턴하면 된다. • 정수로부터 요청을 구분할 수 있으므로 switch-case문으로 분기할 수 있어 편리하다.

  46. 4. CP (Content Provider) • 자료공유 • CP를 만들기 위해 먼저 ContentProvider클래스를 상속받고, 정보를 관리 및 제공하는 메서드를 재정의해야 한다. • onCreate • CP가 로드될 때 호출되며 여기서 제공할 데이터를 준비한다. • DB만이 아닌 내부 배열이나 네트워크의 정보도 이용 가능하다. • DB에 들어있는 정보는 onCreate에서 DB를 열어두면 이용 가능하다. • 데이터의 MIME타입 조사 메서드 • SringgetType (Uri uri) • 정보의 개수에 따라 MIME타입의 형식이 다르며, 강제적인 규칙은 아니다. • 단수 : vnd.회사명.cursor.item/타입 • 복수 : vnd.회사명.cursor.dir/타입 • 그 외 실제 데이터를 제공 및 관리하는 query, insert, delete 등의 메서드를 제공하는 정보에 따라 재정의해야한다.

  47. 4. CP (Content Provider) • EWProvider예제 • EnglishWord프로젝트를 확장하여 CP컴포넌트를 추가한다. • CP는 응용 프로그램에 존재하는 데이터를 외부로 공개하는 역할을 한다.

  48. 4. CP (Content Provider) • EWProvider예제

  49. 4. CP (Content Provider) • 규정대로 URI를 작성하되 패키지명 다음에 액티비티 이름인 EnglishWord를 추가한다. • UriMtcher타입의 헬퍼 Matcher를 정적 멤버로 선언, 정적 초기화블록에서 두 개의 URI형식을 등록한다. - word패스로 끝나면 모든 단어를 전부 요청하고, word뒤에 임의의 단어가 있을 시엔 이 단어만 요청하며, 각각 1, 2의 정수값을 맵핑한다. • - 이후 CP의 나머지 코드는 match메서드가 리턴한 정수만 확인하면 된다. • onCreate에서 DB를 오픈한다. • - 액티비티에서 DB헬퍼를 제작해 두었으므로 getWritableDatabase메서드를 호출,DB객체를 오픈할 수 있다. • - getReadableDatabase로 열면 읽기만 가능한 DB객체를 오픈한다. • getType메서드 • - 규정대로 MIME타입을 정의한다. • query메서드 • - 실제 데이터를 제공한다. • - 인수로 전달된 uri를 분석. 요청받은 데이터를 커서에 실어 리턴한다. • - 단어 전체 : dic테이블 전체를 덤프하여 리턴. • - 한 단어만 : where절을 작성하여 요구한 단어만 조사한 뒤 리턴. • - id에 해당하는 값을 uri.getPathSegments().get(1)로 구하여 where절의 eng필드와 비교한다.

  50. 4. CP (Content Provider) • 조사된 정보는 커서로 리턴된다. - 클라이언트는 커서를 읽어 CP가 제공한 정보를 이용하며, 예제에서는 SQL문을 바로 실행했다. - 정렬 순서를 맞추려면 order by, 특정 열만 요구한다면 원하는 열을 SELECT문에 나열한다. - CP요청이 DB쿼리와 유사한 형태로 전달되므로 db의 query메서드를 호출해도 동일한 결과를 얻을 수 있다. • insert메서드 - 행 하나를 삽입하며, 하나의 레코드에 대해 수행되므로 단수, 복수를 구분할 필요 없다. - DB의 insert메서드로 레코드를 그대로 넘긴다. - 삽입 성공 시 notifyChange메서드를 호출하여 변경 사실을 통보하고, DB에 연결된 어댑터 뷰는 삽입된 레코드를 인식하기 위해 갱신된다. • delete, update 메서드 - 복수 : DB의 대응되는 메서드를 그대로 호출한다. - 단수 : 조건은 URI를 통해 전달될 수도 있고 selection인수를 통해 전달될 수 있기 때문에 URI의 끝에 있는id를 읽어 where절에 조건을 추가하고 둘 다 AND절로 연결한다. - 특정 조건을 만족하는 레코드만을 대상을 할 경우는조건절을 따로 전달해야 한다. - 삭제 및 갱신의 경우도 SQL문으로 실행 가능하다. • 마지막으로 CP를 매니페스트에 등록한다. - application태그 아래, activity와 같은 수준에 아래의 태그를 추가하여CP의 이름과 제공자명을 밝혀놓는다. • <provider android:name=“EWProvider” • android:authorities=“exam.data.EnglishWord”/> • - 매니페스트에 등록해 놓으면 이후 시스템은 정보를 요청하는 쪽의 URI와 매니페스트의URI를 비교하여 제공자가 일치하는 CP를 호출한다. • ※ 반드시 모든 메서드를 다 구현할 필요는 없으며, 필요에 따라 일부 생략 가능하다.

More Related