12Àå PDF

Similar documents
[ 그림 8-1] XML 을이용한옵션메뉴설정방법 <menu> <item 항목ID" android:title=" 항목제목 "/> </menu> public boolean oncreateoptionsmenu(menu menu) { getme

어댑터뷰

안드로이드기본 11 차시어댑터뷰 1 학습목표 어댑터뷰가무엇인지알수있다. 리스트뷰와스피너를사용하여데이터를출력할수있다. 2 확인해볼까? 3 어댑터뷰 1) 학습하기 어댑터뷰 - 1 -

( )부록

2 Application Name: Day10_yhg <LinearLayout android:layout_weight="3" > /> an

2) 활동하기 활동개요 활동과정 [ 예제 10-1]main.xml 1 <LinearLayout xmlns:android=" 2 xmlns:tools="

13ÀåÃß°¡ºÐ

학습목표 메뉴를추가하는방법을이해하고실습할수있다. 프로그램의기본설정 (settings) 을정의하는방법을알고실습할수있다. 대화상자를여는방법을알고실습할수있다. 로그메시지로디버깅하는방법을이해한다. 디버거로디버깅하는방법을이해한다.

9 차시고급위젯다루기 1 학습목표 날짜 / 시간과관련된위젯을배운다. 웹뷰를사용하여간단한웹브라우저기능을구현한다. 매니패스트파일의설정법을배운다. 2 확인해볼까? 3 날짜 / 시간위젯 1) 활동하기 활동개요

헬로, 안드로이드 13 주차 SQL 활용하기 (2) 강대기동서대학교컴퓨터정보공학부

Daum 카페

03장

학습목표 선언하여디자인을하는방법을이해하고, 실행할수있다. 시작화면을만드는방법과대체리소스를사용하는방법을이해하고실행할수있다. About 과같은상자를구현하고, 테마를적용하는법을이해하고실행할수있다.

Studuino소프트웨어 설치

슬라이드 1

01장

리니어레이아웃 - 2 -

아이콘의 정의 본 사용자 설명서에서는 다음 아이콘을 사용합니다. 참고 참고는 발생할 수 있는 상황에 대처하는 방법을 알려 주거나 다른 기능과 함께 작동하는 방법에 대한 요령을 제공합니다. 상표 Brother 로고는 Brother Industries, Ltd.의 등록 상

[ 그림 7-1] 프로젝트 res 폴더 이미지뷰 [ 예제 7-1] 이미지뷰 1 <LinearLayout 2 ~~~~ 중간생략 ~~~~ 3 android:orientation="vertical" > 4 <ImageView

다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");

Microsoft Word - src.doc

쉽게 풀어쓴 C 프로그래밊

Microsoft PowerPoint - CSharp-10-예외처리

PowerPoint Presentation

JAVA PROGRAMMING 실습 08.다형성

Spring Boot/JDBC JdbcTemplate/CRUD 예제

슬라이드 1

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

Microsoft Word - ntasFrameBuilderInstallGuide2.5.doc

C++ Programming

12 주차 인텐트

Microsoft PowerPoint App Fundamentals[Part1](1.0h).pptx

PowerPoint 프레젠테이션

안드로이드2_14

Spring Data JPA Many To Many 양방향 관계 예제

Microsoft PowerPoint - 11주차_Android_GoogleMap.ppt [호환 모드]

View Licenses and Services (customer)

Microsoft PowerPoint App Fundamentals[Part1].pptx

Android Master Key Vulnerability

슬라이드 1

Microsoft PowerPoint - Java7.pptx

Microsoft PowerPoint App Fundamentals[Part2].pptx

REMON Android SDK GUIDE (SDK Version 1.4.1) 1 / 25

PowerPoint Presentation

PowerPoint Presentation

Microsoft PowerPoint - 15주차(최종).pptx

Mobile Service > IAP > Android SDK [ ] IAP SDK TOAST SDK. IAP SDK. Android Studio IDE Android SDK Version (API Level 10). Name Reference V

오버라이딩 (Overriding)

PowerPoint 프레젠테이션

IP 심화 라우팅프로토콜적용시 라우팅테이블에서 이니셜이있는네트워크를설정하는것 : onnected 직접연결된네트워크를의미한다. 그러므로라우팅은 나는이런네트워크와연결되어있다. 를직접연결된라우터들에게알려주는것 1>en 1#conf t 1(config)#router rip 1

2 단계 : 추상화 class 오리 { class 청둥오리 extends 오리 { class 물오리 extends 오리 { 청둥오리 mallardduck = new 청둥오리 (); 물오리 redheadduck = new 물오리 (); mallardduck.swim();

오핀 (OFIN) SDK Guide Fintech Mobile SDK Guide - Android V 1.0 OPPFLIB 1

PowerPoint 프레젠테이션

윈도우시스템프로그래밍

OpenCV와 함께하는 컴퓨터 비전 프로그래밍 캠프

rosaec_workshop_talk

Microsoft PowerPoint - 04-UDP Programming.ppt

목차 1. 시스템요구사항 암호및힌트설정 ( 윈도우 ) JetFlash Vault 시작하기 ( 윈도우 ) JetFlash Vault 옵션 ( 윈도우 )... 9 JetFlash Vault 설정... 9 JetFlash Vault

Microsoft PowerPoint UI-Event.Notification(1.5h).pptx

Windows 8에서 BioStar 1 설치하기

쉽게 풀어쓴 C 프로그래밍

gnu-lee-oop-kor-lec06-3-chap7

슬라이드 1

슬라이드 1

헬로, 안드로이드 7 주차 멀티미디어 강대기동서대학교컴퓨터정보공학부

슬라이드 1

Eclipse 와 Firefox 를이용한 Javascript 개발 발표자 : 문경대 11 년 10 월 26 일수요일

@OneToOne(cascade = = "addr_id") private Addr addr; public Emp(String ename, Addr addr) { this.ename = ename; this.a

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

PowerPoint Template

50_1953.pdf

PowerPoint Presentation

* Factory class for query and DML clause creation * tiwe * */ public class JPAQueryFactory implements JPQLQueryFactory private f

q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2

Visual Basic 반복문

Microsoft PowerPoint - ch09 - 연결형리스트, Stack, Queue와 응용 pm0100

쉽게 풀어쓴 C 프로그래밍

PowerPoint Presentation

- JPA를사용하는경우의스프링설정파일에다음을기술한다. <bean id="entitymanagerfactory" class="org.springframework.orm.jpa.localentitymanagerfactorybean" p:persistenceunitname=

PowerPoint Presentation

슬라이드 1

ISP and CodeVisionAVR C Compiler.hwp

JVM 메모리구조

헬로, 안드로이드 11 주차 위치파악하기와감지하기 강대기동서대학교컴퓨터정보공학부

슬라이드 1

rmi_박준용_final.PDF

게임 기획서 표준양식 연구보고서

학습목표 SQLite 가뭔지알고, 이를사용할줄안다. SQL 의기본적인사용법들을안다. SQLite 을이용해기본적인데이터베이스응용프로그램을작성할수있다. 행을추가하는기본적인데이터베이스응용프로그램을작성할수있다. 쿼리를실행하는기본적인데이터베이스응용프로그램을작성할수있다. 쿼리결과

1

gnu-lee-oop-kor-lec10-1-chap10

PowerPoint Presentation

JUNIT 실습및발표

(8) getpi() 함수는정적함수이므로 main() 에서호출할수있다. (9) class Circle private double radius; static final double PI= ; // PI 이름으로 로초기화된정적상수 public

이것은리스트뷰의 setadapter 메소드에잘표현되어있습니다. setadapter 는리스트뷰에사용할데이터객체를넘겨주는메소드입니다. 일반적으로생각한다면 ArrayAdapter 객체를생성하여사용할데이터를저장할것이고데이터가저장된 ArrayAdapter 객체를 setadapt

Cluster management software

제8장 자바 GUI 프로그래밍 II

제11장 프로세스와 쓰레드

Design Issues

Microsoft PowerPoint UI-Layout.Menu.pptx

안드로이드애플리케이션과통합하는데는자바가편하므로대표적인두가지라이브러리를비교해보자. 자바 ID3 태그라이브러리 jaudiotagger ID3v1, ID3v1.1, Lyrics3v1, Mp3, Mp4 (Mp4 오디오, M4a 지원범위 Lyrics3v2, ID3v2.2, ID

Transcription:

547 CHAPTER 12 라이브폴더 10 장에서는안드로이드에서의 OpenGL 인터페이스에대해자세히설명했으며, 11 장에서 는안드로이드플랫폼에서애플리케이션의환경설정을관리하는방법을설명했다. 본 장에서는안드로이드플랫폼에서의또한가지고급주제인라이브폴더 live folder 에대해설명하겠다. 라이브폴더는안드로이드 SDK 1.5 버전부터도입되었으며, 개발자는라이브폴더를통해기기의기본시작화면 ( 이하 메인페이지 로표기 ) 에연락처, 메모, 미디어등의콘텐트프로바이더를표시할수있다. 안드로이드의연락처콘텐트프로바이더같은콘텐트프로바이더가라이브폴더를통해메인페이지상에표시되면, 연락처데이터베이스안에서연락처가추가 / 삭제 / 변경될때이라이브폴더는자동으로새로고침된다. 이러한라이브폴더의정의, 라이브폴더구현방법, 라이브폴더를 라이브 하게만드는방법에대해알아보겠다. 라이브폴더탐구 RSS 리더의용도가웹사이트를발행하는것이라면, 안드로이드라이브폴더의용도는콘텐트프로바이더 content provider 라할수있다. 3장에서콘텐트프로바이더가 URI를사용해서정보를제공하는웹사이트와흡사하다고설명한바있다. 각기독자적인방식으로정보를발행하는웹사이트들이급증함에따라, 사용자가그렇게확장되는규모의정보를하나의리더에서읽을수있도록여러사이트들로부터정보를수집할필요성이생겼다. 이때문에 RSS가고안되었다. RSS는전혀다른정보들을공통된패턴으로보여준다. 패턴이공통되므로, 콘텐

548 CHAPTER 12 라이브폴더 트의구조만일관적이라면한번의리더설계로모든콘텐트를읽을수있다. 라이브폴더는개념상별로다르지않다. RSS 리더에웹사이트콘텐트를발행하는공통인터페이스가들어있듯이, 라이브폴더에는안드로이드의콘텐트프로바이더에대한공통인터페이스가정의돼있다. 콘텐트프로바이더가이프로토콜에부합하기만하면안드로이드는기기의메인페이지에라이브폴더아이콘을생성해서그콘텐트프로바이더를표현할수있다. 사용자가이라이브폴더아이콘을클릭하면시스템은그콘텐트프로바이더와통신하게된다. 그러면콘텐트프로바이더는커서를반환하게된다. 라이브폴더콘트랙트에따라, 이커서에는사전정의된열들이들어있어야한다. 그런다음이커서는 ListView나 GridView를통해시각적으로표현된다. 이러한공통형식이라는개념을이용하는라이브폴더의원리는다음과같다. 1. 우선사용자가콘텐트프로바이더에서가져오는행컬렉션을표현하는아이콘을메인페이지에생성한다. 이연결은사용자가아이콘과함께 URI를지정함으로써이뤄진다. 2. 사용자가아이콘을클릭하면시스템은그 URI를받아사용하여콘텐트프로바이더를호출한다. 콘텐트프로바이더는커서를통해행컬렉션을반환한다. 3. 커서에라이브폴더가필요로하는열들 ( 이름, 설명, 행이클릭될때호출할프로그램 ) 이존재한다면시스템은 ListView나 GridView를통해그행들을표현한다. 4. ListView와 GridView에는내부데이터저장소가변경되는순간자체데이터를업데이트하는기능이있으므로이뷰들을 라이브 하다고표현할수있으며, 라이브폴더 라는이름이붙여지게된것도이때문이다. 라이브폴더에적용되는주요원칙은두가지다. 첫째원칙은, 모든커서의열이름이같아야한다는점이다. 이원칙으로인해안드로이드는라이브폴더를타깃으로하는모든커서를같은식으로취급할수있다. 둘째원칙은, 내부커서데이터에발생한모든변경사항을찾아서그에맞게수정할방법이안드로이드뷰에정의돼있어야한다는점이다. 이둘째원칙은라이브폴더에만국한되는사항이아니라안드로이드 UI에속하는모든뷰 ( 특히커서를이용하는뷰 ) 에기본적으로적용된다. 지금까지라이브폴더가무엇인지에대해설명했다. 그럼다음두개의절에걸쳐라이브폴더프레임워크에대해체계적으로알아보자. 첫번째절에서는라이브폴더의전반적인최종사용자경험에대해알아보겠는데, 이를통해라이브폴더에대한이해가훨씬확고해질것이다.

라이브폴더탐구 549 두번째절에서는라이브폴더를진정으로라이브하게하기위한올바른라이브폴더생성방법에대해설명하겠다. 라이브폴더를 라이브 하게만드는데에는약간의부가작업이필요하므로, 이런라이브폴더의불명확한측면에대해설명하겠다. 라이브폴더사용법 라이브폴더는기기의메인페이지를통해최종사용자에게공개된다. 사용자의라이브폴더사용절차는다음과같다. 1. 기기의메인페이지로이동한다. 2. 메인페이지의콘텍스트메뉴를띄운다. 콘텍스트메뉴를띄우려면메인페이지의빈공간에서롱클릭 long clicking 하면된다. 3. 콘텍스트메뉴의 Folders 항목으로이동해서클릭하면가용라이브폴더들이뜬다. 4. 그목록에서메인페이지에띄울라이브폴더명을선택해서클릭하자. 그러면메인페이지에선택한라이브폴더를나타내는아이콘이생성된다. 5. 4단계에서설정한라이브폴더아이콘을클릭해서정보행들 ( 라이브폴더에표현되는데이터 ) 을 ListView나 GridView 안에가져온다. 6. 여러행중하나를클릭해서그데이터행을표시할방법이정의된애플리케이션을호출한다. 7. 애플리케이션이표시하는추가메뉴옵션들을이용하여원하는항목을보거나조작한다. 애플리케이션의메뉴옵션들을이용하여호환되는새항목을생성할수도있다. 8. 해당항목 ( 들 ) 에변경이발생하면라이브폴더표시내용에자동으로반영된다. 그럼캡처화면을보면서위의절차대로직접라이브폴더를사용해보자. 먼저그림 12 1에서처럼 1단계의안드로이드메인페이지로가자. 이메인페이지는본인이사용중인안드로이드버전에따라외관이약간다를수있다.

550 CHAPTER 12 라이브폴더 그림 12-1 안드로이드메인페이지 이메인페이지의빈공간을롱클릭하면그림 12 2 처럼콘텍스트메뉴가뜬다. 그림 12-2 안드로이드메뉴페이지의콘텍스트메뉴

라이브폴더탐구 551 하위옵션 Folders를클릭하면그림 12 3처럼존재하는라이브폴더들목록을표시하는하위메뉴가뜬다. 다음절에서라이브폴더를생성해볼텐데, 지금은일단그림 12 3처럼우리가원하는라이브폴더가이미생성돼있으며그폴더이름이 New live folder라고가정하자. 그림 12-3 가용라이브폴더목록보기 New live folder를클릭하면안드로이드는메인페이지에그라이브폴더를표현하는아이콘을생성한다. 우리가살펴보는예에서는이폴더의이름이그림 12 4처럼 Contacts Live Folder의약어인 Contacts LF이다. 이라이브폴더는연락처데이터베이스에들어있는연락처들을표시한다 ( 이폴더명을지정하는방법은나중에예제 12 2의 AllContactsLiveFolder CreatorActivity 클래스에대해다루면서설명하겠다 ).

552 CHAPTER 12 라이브 폴더 그림 12-4 메인 페이지의 라이브 폴더 아이콘 다음 절에서 액티비티가 Contacts LF 폴더를 생성함을 살펴볼 텐데, 일단 지금은 사용자 경 험이 관련돼 있는 한 그림 12 5처럼 Contacts LF 아이콘을 클릭해서 ListView에 표시되는 연락처 목록을 볼 수 있다. 그림 12-5 라이브 폴더 연락처 표시

라이브폴더탐구 553 기기에존재하는연락처수에따라표시되는연락처목록의모습은다를수있다. 여러개의연락처중하나를클릭하면그림 12 6처럼그연락처의세부사항이표시된다. 그림 12-6 라이브폴더연락처열기 하단의 Menu 버튼을클릭하면그림 12 7 처럼그개별연락처를조작할수있는메뉴가뜬다. 그림 12-7 개별연락처의메뉴옵션

554 CHAPTER 12 라이브폴더 그연락처를수정하기위해선택하면그림 12 8 과같은화면이뜬다. 그림 12-8 연락처세부항목편집 라이브폴더의 라이브 한특성을보려면, 이연락처를삭제하거나새연락처를생성해보면된다. 그런다음 Contacts LF의라이브폴더뷰로돌아가면그러한변경사항들이반영됨을알수있다. 라이브폴더뷰로돌아가려면 Contacts LF 폴더가뜰때까지계속 Back 버튼을클릭하면된다. 라이브폴더제작 라이브폴더의정의에대해알아보았으니, 이제라이브폴더생성방법을설명하겠다. 일단라이브폴더가생성되면, 그라이브폴더를이용해서메인페이지에그라이브폴더에해당하는아이콘을생성할수있다. 더불어라이브폴더의 라이브 한부분의원리도설명하겠다. 라이브폴더를생성하려면액티비티와전용콘텐트프로바이더가필요하다. 안드로이드는그림 12 3처럼이액티비티의 라벨 을사용해서존재하는라이브폴더들의목록을채운다. 그리고안드로이드는이액티비티를호출해서 URI를알아낸다. 이 URI를호출하면안드로이드는열목록을가져와서표시하게된다.

라이브폴더탐구 555 그액티비티에의해알아낸 URI는행들을반환하는전용콘텐트프로바이더를참조해야한다. 콘텐트프로바이더는이행들을명확하게정의된커서를통해반환한다. 이커서를 명확하게정의된 well defined 커서라고부르는이유는이커서에이미알고있는사전정의열이름들이들어있기때문이다. 일반적으로는이두엔티티를애플리케이션안에패키지화한후그애플리케이션을기기에설치하게된다. 이작업을원활하게해주는일부보조파일도필요하다. 다음파일들로구성된샘플을보면서이개념들을설명하고예를들겠다. AndroidManifest.xml: 이파일에는라이브폴더에대한정의를생성하기위해호출돼야할액티비티가정의돼있다. AllContactsLiveFolderCreatorActivity.java: 이액티비티는연락처데이터베이스에들어있는모든연락처를표시할수있는라이브폴더에대한정의를공급한다. MyContactsProvider.java: 이콘덴트프로바이더는연락처의커서를반환하는라이브폴더 URI에응답하게된다. 이프로바이더는내부적으로안드로이드에내장된연락처콘텐트프로바이더를사용한다. MyContactsProvider.java: 이콘텐트프로바이더는연락처들이들어있는커서를반환할라이브폴더 URI에응답하게된다. 이프로바이더는내부적으로안드로이드에포함돼있는연락처콘텐트프로바이더를사용한다. BetterCursorWrapper.java: 이파일은 MyCursor가재질의를구성하는데필요하다. SimpleActivity.java: 이간단한액티비티는본인이개발한프로젝트테스트에사용할수있는선택적파일이다. 최종설치버전에는이파일이필요없다. 라이브폴더의원리를이해하기위해다음절부터위파일들각각을자세히살펴보자. AndroidManifest.xml AndroidManifest.xml 파일은지금까지수없이다뤘으므로이미익숙하다. 모든안드로이드애플리케이션에공통으로필요한파일이다. 예제 12 1에서보듯이, 주석처리로넣은이파일의라이브폴더부분은라이브폴더생성을담당하는 AllContactsLiveFolderCreatorActivity라는액티비티가존재함을나타낸다. 이사실은액션이 android.intent.action.create_live_folder

556 CHAPTER 12 라이브폴더 인인텐트선언을통해표현된다. 이액티비티의라벨 New live folder 는그림 12 3에서처럼메인페이지에뜰콘텍스트메뉴에표시될문구다. 라이브폴더사용법 절에서설명했듯이, 콘텍스트메뉴를띄우려면메인페이지에서롱클릭하면된다. 예제 12-1 AndroidManifest.xml 파일에라이브폴더정의삽입 <?xml version="1.0" encoding="utf 8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ai.android.livefolders" android:versioncode="1" android:versionname="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".simpleactivity" android:label="@string/app_name"> <intent filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent filter> </activity> <! 라이브폴더 > <activity android:name=".allcontactslivefoldercreatoractivity" android:label="new live folder " android:icon="@drawable/icon"> <intent filter> <action android:name="android.intent.action.create_live_folder" /> <category android:name="android.intent.category.default" /> </intent filter> </activity> <provider android:authorities="com.ai.livefolders.contacts" android:multiprocess="true" android:name=".mycontactsprovider" /> </application> <uses sdk android:minsdkversion="8" /> <uses permission android:name="android.permission.read_contacts"> </uses permission> </manifest>

라이브폴더탐구 557 예제 12 1의코드에서또한가지중요한부분은프로바이더선언이다. 프로바이더선언에 URI가 content://com.ai.livefolders.contacts로지정돼있으며프로바이더클래스 MyContacts Provider에의해서비스된다. 이프로바이더는그림 12 5처럼해당라이브폴더아이콘이클릭되는순간 ListView를채울커서를공급한다. 라이브폴더액티비티 AllContactsLiveFolder CreatorActivity에는이 URI가무엇인지정의돼있어야하며, 호출될때그 URI를안드로이드에반환해야한다. 안드로이드는메인페이지에서라이브폴더아이콘생성을위해라이브폴더이름이선택될때이액티비티를호출한다. 라이브폴더프로토콜에따라, CREATE_LIVE_FOLDER 인텐트는그림 12 3처럼메인페이지의콘텍스트메뉴로하여금 AllContactsLiveFolderCreatorActivity를 New live folder 라는제목의옵션으로표시할수있게한다. 이메뉴옵션을클릭하면그림 12 4처럼메인페이지에아이콘이생성된다. 이아이콘은이미지와라벨로구성되게끔 AllContactsLiveFolderCreatorActivity에정의된다. 예제 12 2의 AllContactsLiveFolderCreatorActivity 코드에서는이라벨을 Contacts LF로지정했다. 그럼이라이브폴더생성자의소스코드를살펴보자. AllContactsLiveFolderCreatorActivity.java 예제 12 2에서보듯이 AllContactsLiveFolderCreatorActivity 클래스의기능은오직라이브폴더의생성자역할을하는것뿐이다. AllContactsLiveFolderCreatorActivity를라이브폴더의템플릿으로생각하면이해하기쉽다. 메인페이지의콘텍스트메뉴에있는 Folders 옵션을통해이액티비티가클릭될때마다, 이액티비티는메인페이지에라이브폴더를생성한다. 이액티비티는본연의임무를완수하기위해호출자 ( 여기서는메인페이지나라이브폴더프레임워크 ) 에게라이브폴더명, 라이브폴더아이콘에사용할이미지, 데이터가존재하는 URI, 표시모드 ( 리스트또는그리드 ) 를전달한다. 그러면정보를전달받은이호출자프레임워크는메인페이지에라이브폴더아이콘을생성한다. 라이브폴더에필요한모든콘트랙트에대해서는 android.provider.livefolders 클래스에관해설명돼있는안드로이드 SDK 문서를참조하자. 참고

558 CHAPTER 12 라이브폴더 예제 12-2 AllContactsLiveFolderCreatorActivity 소스코드 public class AllContactsLiveFolderCreatorActivity extends Activity @Override protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); final Intent intent = getintent(); final String action = intent.getaction(); if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) setresult(result_ok, createlivefolder(mycontactsprovider.contacts_uri, "Contacts LF", R.drawable.icon)); else setresult(result_canceled); finish(); private Intent createlivefolder(uri uri, String name, int icon) final Intent intent = new Intent(); intent.setdata(uri); intent.putextra(livefolders.extra_live_folder_name, name); intent.putextra(livefolders.extra_live_folder_icon, Intent.ShortcutIconResource.fromContext(this, icon)); intent.putextra(livefolders.extra_live_folder_display_mode, LiveFolders.DISPLAY_MODE_LIST); return intent; createlivefolder 메서드는기본적으로자신을호출한인텐트상의값들을설정한다. 이인텐트가호출자에반환되면, 호출자에는다음정보가들어있게된다. 라이브폴더명라이브폴더아이콘이미지표시모드 : 리스트또는그리드

라이브폴더탐구 559 데이터, 또는데이터를호출할콘텐트 URI 위의정보만있으면그림 12 4와같이라이브폴더아이콘을생성할수있다. 사용자가이아이콘을클릭하면시스템은그 URI를호출해서데이터를가져온다. 표준화된커서를공급하는일은이 URI로식별되는콘텐트프로바이더가담당한다. 그럼다음절에서그콘텐트프로바이더 MyContactsProvider 클래스의코드를살펴보자. MyContactsProvider.java MyContactsProvider의기능은다음과같다. 1. 전달받은 content://com.ai.livefolders.contacts/contacts 형태의 URI를식별한다. 2. content://contacts/people/ 로식별되는안드로이드내장연락처콘텐트프로바이더를내부적으로호출한다. 3. 커서에있는모든행을읽어들여서, 그행들을라이브폴더프레임워크에필요한알맞은열이름들을사용해다시 MatrixCursor 같은커서에매핑한다. 4. 또다른커서로 MatrixCursor를포장해서, 이포장된커서에대한재질의가필요할때연락처콘텐트프로바이더를호출할수있게한다. MyContactsProvider의코드는예제 12 3과같다. 중요한부분은볼드체로표기했다. 예제 12-3 MyContactsProvider 소스코드 public class MyContactsProvider extends ContentProvider public static final String AUTHORITY = "com.ai.livefolders.contacts"; // 라이브폴더생성메서드로전달되는 Uri public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITY + "/contacts" ); // 이 URI 를구별 private static final int TYPE_MY_URI = 0; private static final UriMatcher URI_MATCHER; static URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); URI_MATCHER.addURI(AUTHORITY, "contacts", TYPE_MY_URI); @Override

560 CHAPTER 12 라이브폴더 public boolean oncreate() return true; @Override public int bulkinsert(uri arg0, ContentValues[] values) return 0; // 삽입할것이없음 // 라이브폴더에필요한열들 // 다음은라이브폴더의콘트랙트다. private static final String[] CURSOR_COLUMNS = new String[] BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION, LiveFolders.INTENT, LiveFolders.ICON_PACKAGE, LiveFolders.ICON_RESOURCE ; // 행이없을경우에러메시지를표시하는대신에 // 같은라이브폴더열들이존재함을알림 private static final String[] CURSOR_ERROR_COLUMNS = new String[] BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION ; // 에러메시지행 private static final Object[] ERROR_MESSAGE_ROW = new Object[] 1, // ID " 연락처가없습니다 ", // 이름 " 연락처데이터베이스를확인하세요 " // 설명 ; // 사용할에러커서 private static MatrixCursor serrorcursor = new MatrixCursor(CURSOR_ERROR_COLUMNS); static serrorcursor.addrow(error_message_row);

라이브폴더탐구 561 // 연락처데이터베이스에서가져올열들 private static final String[] CONTACTS_COLUMN_NAMES = new String[] Data._ID, Data.DISPLAY_NAME, Data.TIMES_CONTACTED, Data.STARRED ; public Cursor query(uri uri, String[] projection, String selection, String[] selectionargs, String sortorder) // URI 를알아내서일치하지않으면에러를반환 int type = URI_MATCHER.match(uri); if(type == UriMatcher.NO_MATCH) return serrorcursor; Log.i("ss", " 질의가호출되었습니다 "); try MatrixCursor mc = loadnewdata(this); mc.setnotificationuri(getcontext().getcontentresolver(), Uri.parse("content://contacts/people/")); MyCursor wmc = new MyCursor(mc,this); return wmc; catch (Throwable e) return serrorcursor; public static MatrixCursor loadnewdata(contentprovider cp) MatrixCursor mc = new MatrixCursor(CURSOR_COLUMNS); Cursor allcontacts = null; try allcontacts = cp.getcontext().getcontentresolver().query(

562 CHAPTER 12 라이브폴더 Contacts.CONTENT_URI, CONTACTS_COLUMN_NAMES, null, // 행필터 null, Contacts.DISPLAY_NAME); // 정렬기준 while(allcontacts.movetonext()) String timescontacted = " 연락횟수 : "+allcontacts.getint(2); Object[] rowobject = new Object[] allcontacts.getlong(0), allcontacts.getstring(1), timescontacted, Uri.parse("content://contacts/people/" +allcontacts.getlong(0)), cp.getcontext().getpackagename(), R.drawable.icon ; mc.addrow(rowobject); return mc; finally allcontacts.close(); // ID // 이름 // 설명 // 인텐트 URI // 패키지 // 아이콘 @Override public String gettype(uri uri) // 이래퍼프로바이더를대상으로하는 // 전달받은 URI 의마임타입을반환 // 일반적형태는다음과같다. // "vnd.android.cursor.dir/vnd.google.note" return Data.CONTENT_TYPE; public Uri insert(uri uri, ContentValues initialvalues) throw new UnsupportedOperationException(" 이것은래퍼에불과하므로삽입할수없습니다 "); @Override

라이브폴더탐구 563 public int delete(uri uri, String selection, String[] selectionargs) throw new UnsupportedOperationException(" 이것은래퍼에불과하므로삽입할수없습니다 "); public int update(uri uri, ContentValues values, String selection, String[] selectionargs) throw new UnsupportedOperationException(" 이것은래퍼에불과하므로삽입할수없습니다 "); 예제 12 4 의코드에들어있는열들에는라이브폴더에필요한표준열들이포함된다. 예제 12-4 라이브폴더요건을충족시키기위해필요한열들 private static final String[] CURSOR_COLUMNS = new String[] BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION, LiveFolders.INTENT, LiveFolders.ICON_PACKAGE, LiveFolders.ICON_RESOURCE ; 예제 12 4에서 INTENT 항목을제외한대부분의열은이름만봐도무엇인지알수있다. 그림 12 5를보면 NAME은목록에표시되는해당항목의제목에관련된것임을알수있다. DESCRIPTION은그목록항목의 NAME 밑에표시된다. INTENT 필드는사실상콘텐트프로바이더안의해당항목 URI를참조하는문자열필드다. 안드로이드는사용자가해당항목을클릭하면이 URI를통해 VIEW 액션을사용하게된다. 안드로이드는내부적으로이문자열 URI로부터 INTENT를파생시키므로, 이문자열필드를 INTENT 필드라고부른다. 나머지두개의필드는목록안에표시되는 ICON에관련된것이다. 다시말하지만, 아이콘은그림 12 5에서볼수있다. 연락처데이터베이스의값이이열들에공급되는원리를이해하려면예제 12 3을분석하자.

564 CHAPTER 12 라이브폴더 그리고위의래퍼콘텐트프로바이더 MyContactsContentProvider는데이터변경사항을감시하도록내부커서에명령하기위해예제 12 5의코드를실행한다. 예제 12-5 Cursor 를사용해서 URI 등록 MatrixCursor mc = loadnewdata(this); mc.setnotificationuri(getcontext().getcontentresolver(), Uri.parse("content://contacts/people/")); loadnewdata() 함수는연락처프로바이더에서연락처들을가져오고예제 12 4의열들로구성된 MatrixCursor를생성한다. 그런다음, 해당 URI(content://contacts/people) 를통해참조되는데이터가어떤식으로든변경될경우그사실을 ContentResolver가커서에게통보할수있도록 MatrixCursor에 ContentResolver를사용해서자체를등록하도록명령한다. 감시할 URI는 MyContactsProvider 콘텐트프로바이더의 URI가아니라안드로이드내장연락처콘텐트프로바이더의 URI임에유의하자. 그이유는 MyContactsProvider가그저 진짜 콘텐트프로바이더를포장하고있는래퍼에불과하기때문이다. 그러므로이커서는래퍼가아니라하위에들어있는콘텐트프로바이더를감시해야한다. MatrixCursor를예제 12 6과같이손수작성한커서로포장한점에도유의하자. 예제 12-6 커서포장하기 MatrixCursor mc = loadnewdata(this); mc.setnotificationuri(getcontext().getcontentresolver(), Uri.parse("content://contacts/people/")); MyCursor wmc = new MyCursor(mc,this); 커서를포장해야하는이유를이해하려면뷰가변경된콘텐트를업데이트하기위해어떤작업을하는지알아야한다. Contacts 같은콘텐트프로바이더는일반적으로질의메서드구현부안에 URI를등록해서변경사항을감시하라고커서에게명령한다. 이작업은 cursor.setnot ificationuri를통해이뤄진다. 그러면그커서는콘텐트프로바이더에이 URI와자식 URI 들을등록한다. 그런다음그콘텐트프로바이더에서삽입이나삭제가발생하면, 삽입이나삭제작업의코드는특정 URI를통해식별되는행들에들어있는데이터가변경됐음을알리는이벤트를발생시켜야한다.

라이브폴더탐구 565 그러면커서는재질의를통해업데이트되기시작하며, 뷰도그에따라업데이트된다. 한가지문제는 MatrixCursor가이재질의에연동되지않는다는점이다. SQLiteCursor는연동되지만여기서는열들을새열들에매핑할것이므로 SQLiteCursor를사용할수없다. 이문제를해결하기위해 MatrixCursor를커서래퍼로포장하고, 내부 MatrixCursor를버리고업데이트된데이터를사용해새커서를생성하도록재질의메서드를재정의했다. 더정교하게하려면데이터가변경될때마다새 MatrixCursor를가져와야한다. 그러나안드로이드 Live Folder 프레임워크에포장된바깥쪽커서만반환했다. 이렇게하면, 커서가한개밖에없지만데이터가변경될때하위에새커서가생성될것이라는사실이라이브폴더프레임워크에전달된다. 이것은다음두개의클래스안에구현돼있다. MyCursor.java 예제 12 7에서 MyCursor가처음에 MatrixCursor를통해어떤식으로초기화되는지눈여겨보자. 재질의에서 MyCursor는프로바이더를다시호출해서 MatrixCursor를반환한다. 그러면새 MatrixCursor는 set 메서드를사용해서기존의 MatrixCursor를대체하게된다. 참고이를위해 MatrixCursor의재질의를재정의할수도있었겠지만그클래스에는데이터를초기화하고전부다시시작할방법이정의돼있지않다. 따라서이것이합당한차선책이다 (MyCursor는 BetterCursorWrapper를상속확장한다. 이에대해서는나중에설명하겠다 ). 예제 12-7 MyCursor 소스코드 public class MyCursor extends BetterCursorWrapper private ContentProvider mcp = null; public MyCursor(MatrixCursor mc, ContentProvider incp) super(mc); mcp = incp; public boolean requery()

566 CHAPTER 12 라이브폴더 MatrixCursor mc = MyContactsProvider.loadNewData(mcp); this.setinternalcursor(mc); return super.requery(); 그럼이제커서를포장하는원리를이해하기위해 BetterCursorWrapper 클래스를살펴보자. BetterCursorWrapper.java 예제 12 8의 BetterCursorWrapper 클래스는안드로이드데이터베이스프레임워크에들어있는 CursorWrapper 클래스와아주비슷하다. 다만 BetterCursorWrapper 클래스는 CursorWrapper 클래스와두가지가다르다. 첫째로, 재질의메서드로부터내부커서를대체할 set 메서드가없다. 둘째로, CursorWrapper는 CrossProcessCursor가아닌데, 라이브폴더는프로세스경계를넘나들기때문에일반커서가아니라 CrossProcessCursor를사용해야한다. 예제 12-8 BetterCursorWrapper 소스코드 public class BetterCursorWrapper implements CrossProcessCursor // 메서드들을위임할내부커서를저장 protected CrossProcessCursor internalcursor; // 생성자가크로스프로세스커서를입력으로받음 public BetterCursorWrapper(CrossProcessCursor incursor) this.setinternalcursor(incursor); // 파생클래스의메서드들중하나를초기화할수있음 public void setinternalcursor(crossprocesscursor incursor) internalcursor = incursor; // 위임된모든메서드 public void fillwindow(int arg0, CursorWindow arg1) internalcursor.fillwindow(arg0, arg1); //... 위임된기타메서드들

라이브폴더탐구 567 예제에는전체클래스가나와있지않지만이클립스를사용하면나머지코드를간편히생성할수있다. 이부분클래스를이클립스안에로딩했으면 internalcursor라는변수에커서를놓고우클릭한후 Source Generate Delegated Methods를선택하자. 그러면이클립스는이클래스의나머지코드를자동으로기입한다. 그럼다음절에서이간단한프로젝트완성에필요한간단한액티비티를살펴보자. SimpleActivity.java 예제 12 9의 SimpleActivity.java는라이브폴더용필수클래스는아니지만, 이것을프로젝트에넣으면모든프로젝트의패턴이같아지며이클립스에서디버깅할때애플리케이션을설치해서화면에서보면서할수있다. 예제 12-9 SimpleActivity 소스코드 public class SimpleActivity extends Activity @Override public void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.main); R.layout.main으로식별되는 main.xml에는예제 12 10과같이간단한 XML 레이아웃을작성하면된다. 예제 12-10 간단한 XML 레이아웃파일 <?xml version="1.0" encoding="utf 8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text=" 라이브폴더예제 " /> </LinearLayout>

568 CHAPTER 12 라이브폴더 지금까지이클립스에서샘플라이브폴더프로젝트를작성, 설치, 실행하는데필요한모든내용을설명했다. 끝으로다음절에서라이브폴더사용을연습해보자. 라이브폴더사용테스트라이브폴더프로젝트에필요한위의파일들이전부준비됐으면빌드해서에뮬레이터에설치할수있다. 이애플리케이션을이클립스를통해설치하면에뮬레이터에간단한액티비티가뜬다. 그러면생성된라이브폴더를사용할준비가모두갖춰진다. 기기메인페이지로가면그림 12 1과같은모습일것이다. 라이브폴더사용법 절의맨앞에요약해놓은단계를따라실행하자. 구체적으로설명하자면, 생성한라이브폴더로가서그림 12 4처럼라이브폴더아이콘을생성하자. Contacts LF라는라이브폴더아이콘을클릭하면그림 12 5처럼연락처목록이뜰것이다. 핵심정리 라이브폴더에는메인페이지에가변데이터를표시하는독창적인원클릭기능이있다. 이가변데이터는사실상리스트안에표시되는열들처럼배치될수만있다면어떤것이든될수있다. 이름과설명을통해스스로를식별하고기술하는데이터만들어있어야한다. 대부분의데이터에어떤식으로든이름과설명을넣을수있으므로, 거의모든데이터요소는이요건에부합한다. 이는라이브폴더를통해더세부적인내용을보기위해클릭될때해당데이터를표시할수있는액티비티가존재할경우에도도움이된다. 이데이터는연락처같이로컬에존재할수도있고블로그요약같이네트워크상에존재할수도있다. 본장에서는안드로이드가액티비티를이용해서라이브폴더의콘텐트 URI를알아내는방법을설명했다. 안드로이드는그렇게알아낸 URI를사용해서그라이브폴더의내용으로표시될행컬렉션을가져온다. 이전 URI를사용하여라이브폴더에데이터를공급하는콘텐트프로바이더구현법에대해서도설명했다. 또한라이브폴더커서들의미묘한차이와기존콘텐트프로바이더를라이브폴더의원본으로공개해야할경우어떤메커니즘을사용해야할지에대해서도설명했다. 커서래퍼의필요성과 ContentResolver에등록해서데이터변경사항을가져오는방법에대해알아보았다. 다음장에서는또다른메인페이지혁신기술인메인화면위젯에대해설명하겠다.