신동길 수석 /모바일 클라이언트 개발랩
Naver
간결하고 효율적인
안드로이드 앱 구조와 개발
3.
1.Introduction 2. Architecture
-Application Object
-Life Cycle Redirection 3. Language Tools
-Reflection
-Generics
-Annotation
CONTENTS
3. GUI
-Layout and Automation
-Adapter & AdapterView
-XML Layout & Component Design 4. Data Transfer
-Intent/Bundle
-Scheme & Uri 5. Data Core
-DB and Cursor
-XML/JSON API to Data Object
1.0 Android App에대한 의문
Java가 UI 코드에 적합한 언어인가?
Android API로 프로그램 했을 때 코드가 간결하고 효율적인가?
Activity 효율적으로 프로그래밍 할 수 있는 구조인가?
Xml 기반의 UI 가 좋은 구조화 효율을 가져다 주나?
안드로이드가 서버 API기반의 데이터를 쉽게 처리할 수 있는 구조인가?
SQLite를 많이 사용하는데 효율적인 코드가 나오나?
맨날 바뀌는 서비스 코드에서 효율적인 것은 어떤 걸까?
6.
Q&A
Client Application의구성
1.
DataCore
GUI
Data Transfer
1.1 Application Code구성
70%
Layout Xml
Java Code
25%
UI Data
API Access
DB Table
5%
Intent(Bundle) Data
Uri Data
SharedData
Architecture
7.
Activity
1.2 App의구성 요소와 데이터 전달
Broadcast Receiver
Service
Content
Provider
Application
DB Table
File
Preference
XML/JSON
Data API Connector
Alarm
ListView
WebView
Request(Intent)
Response
(Intent)
Activity
Request(Uri)
ProgramWebViewActivity
ProgramListActivity
UriSchemeActivity
Request(Intent)
Request(Intent)
Data Core
Q&A
Application 객체의특징
Application Context 이며 앱의 프로세스의 생명 주기 같다
- 앱 전체에서 사용하는 요소(BroadcastReceiver,Service,Noti,Alarm 등등)의 초기화가 가능하다.
-전역 변수, 전달 변수 등을 저장할 수 있다. 앱 내 어디에서나 참조 가능하다.
(일반적인 static 변수(또는 singleton)는 LMK에 의해 GC 당할 수 있다)
-앱 전체의 BroadcastReceiver 등의 공통요소를 포함 할 수 있다.
-모든 Activity의 Life Cycle을 처리할 수 있다.
=> App내에서 어디서나 사용할 수 공통 요소의 정의가 가능하다.
2.1 Application 객체(1)
11.
AppContext 는?
Application의singleton으로 정의하여 앱 내에서 어디서나 접근한 공통요소 제공할 수 있음.
2.1 Application의 활용(2)-AppContext
Static method
설 명
Context getContext()
Application Context 리턴
SQLiteDatabase getDB()
앱 내에서 사용한 DB instance 리턴
SharePreferences getAppPref()
SharePreference의 instance 리턴
putValue(String key,Object value)
앱 내에서 공유할 Object 저장
Object getValue(String key,boolean remove)
앱 내에서 공유 Object 반환
post(Runnable r)
UI Thread로 post
postDelayed(Runnable r,int millis)
mills 후에 UI Thread로 post
int dp2px(float dp)
DP를 Pixel로 변환
<표> AppContext에서 제공할 수 있는 공통 기능 예
12.
Q&A
Life CycleRediect 객체? - Activity의 상태를 다른 객체에 전달하기 위해 공통 Activity에 정의된 객체.
-Activity에 Controller, View나 이를 받을 곳에 Controllable을 구현.
-Layout(FrameLayout, …)을 이용하면 XML에 포함할 수 있는 Controller를 만들 수 있음.
-UI 객체의 경우 getContext()로 Base Activity에 접근이 가능하므로 등록 해제가 쉬움
2.2 Life Cycle 제어(1)
13.
2.2 Life Cycle제어(2)
class DeView-LifeCycle
CycleController
+ onStart() :void
+ onResume() :void
+ onPause() :void
+ onStop() :void
+ onDestroy() :void
+ onActivityResult() :void
«interface»
CycleControllerable
+ onStart() :void
+ onResume() :void
+ onPause() :void
+ onStop() :void
+ onDestroy() :void
+ onActivityResult() :void
CycleControllerActiv ity
- mCycleController :CycleController
+ onStart() :void
+ setContentView() :void
+ onResume() :void
+ onPause() :void
+ onStop() :void
+ onDestroy() :void
+ onActivityResult() :void
FragmentActiv ity
FrameLayout
CycleBaseLayout
+ onStart() :void
+ onResume() :void
+ onPause() :void
+ onStop() :void
+ onDestroy() :void
+ onActivityResult() :void
Life Cycle 제어 객체 구조
앱 내에서 공통으로 사용하는 Activiy,Fragment, Layout Base 객체에 Cycle 전달
기능을 추가하면 Life Cycle을 위한 별도의 코딩이 줄어든다.
3.Language Tools
코드를간결하게 만들기 위해서는 이를 위한 도구를 개발
-Inheritance(Derivation)
-Reflection
-Generics
-Annotations
16.
Q&A
Reflection 이란
-클래스의 내부를 들여다 볼 수 있는 도구=> 이를 통해 자동화가 가능하다.
--객체의 Field 나 Method를 이름(String)으로 생성&접근할 수 있는 방법.
3.1 Reflection(1)
class Record {
public String nickName;
}
Record instance = new Record();
Class<?> cls = Record.getClass();
Reflection
Non-Reflection
Field field =cls.getField(“nickName”);
field.set(instance, value);
instance.nickName = value;
Field field2 = cls.getField(“nickName”);
value = (String)field2.get(instance);
String value = instance.nickName;
17.
Q&A
3.1 Reflection(2)-Methods
Class<?> getClass() 의 Methods
Method
Description
Field[] getFields()
부모를 포함한 모든 public field를 리턴한다.
Field[] getDeclaredFields()
현재 클래스의 private를 포함 모든 field를 리턴한다.
Field getField(String name)
Name에 해당하는 Field를 리턴한다.
Method
Description
Type getType()
Returns all fields in a target Object
String getSimpleType()
데이터 타입의 이름만 반환한다.
Object get(Objet instance,String name);
Field의 값을 Object 로 반환한다.
void set(Objet instance,Object value)
Field에 Object 값을 설정한다.
void setAccessible(boolean access);
해당 필드가 private일때 접근 가능 여부를 설정한다.
Field의 Methods
18.
Q&A
Generics 란?-Java 5에서 정의되었으며 C++의 Template과 같이 일반화 된 데이터형을 정의할 수 있다. - Runtime에 자료형을 바꿀 수 있게 한다.
3.2 Generics
class ListCellData<T> extends FrameLayout {
T mData;
int position;
String tag;
};
ListCellData<uri> mCellData;
19.
Q&A
Annotation이란?
-클래스나필드, 메쏘드나 파라메터에 부가적인 정보를 정의 한다.
-파라메터에는 기본 자료형과 .class를 사용할 수 있다.
3.3 Annotation
@DeclareView(id = R.id.listView) ListView listView; … Field listField = getClass().getField(“listView”); DeclareView ann = listField.getAnnotion(DeclareView.class); int id = ann.id(); String name = ann.name();
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DeclareView {
int id() default 0;
String name() default "";
String tag() default "";
String click() default "";
}
4. GUI &Practices
Layout의 분리
-GUI의 관건은 Layout 을 잘 쪼개는 일이다.
-Sublayout-xml vs sublayout controller
-findViewById와 같은 초기화 요소를 최소화 하라
-Layout을 사용하여Cycle을 잘 빼라
-XML에 적절하게 활용하여 고정된 값들을 사용하라
-Activity의 코드를 줄여라
22.
Q&A
4.1 Layout을통한 모듈화
Sub Layout의 활용
-Layout 내에서 xml inflate를 하면 Layout을 Controller로 사용할 수 있고 모듈화 가능
-Layout에 StateControllable을 구현하면 Fragment와 같은 기능 갖는다.
TitleViewLayout extends FrameLayout implements StatControllale
BodyViewLayout
activity_main.xml
panel_title.xml
panel_body.xml
onStart()
onResume()
onPause()
onStop()
onActivityResult()
MainActivity.java
23.
Q&A
4.2 findViewId와Listener자동화 처리
Resource Id Mapping 최적화
-findViewById(id=R.id.xx)를 통한 Resource Mapping이 로직 코드에 포함되지 않도록 하는 자동화 도구를 만든다. 하나의 Controller 에서는 Mapping을 통해 OnClickListener를 최소화 한다.
AS-IS
TO-BE
24.
Q&A
4.3 AdapterViewTemplate(1)
AdapterView의 Modeling을 통한 최적화
- List CellView 를 Layout 기반으로 추상화 하고 Data요소를 가지도록 함
- List CellView에 맞는 공통 Adapter 구현(Generics 활용).
- OnItemClickListener에서 CellView의 데이터를 바로 얻을 수 있음
class DeView-ListAdapter
FrameLayout
ListCellView<T>
+ onCreate(Context) :void
+ inflate(int) :View
+ setData(int, T) :void
BaseAdapter
ListCellViewAdapter<T>
- mDataList :Vector<T>
+ ListCel lViewAdapter(Class<?>) :void
+ getView(int, View, ViewGroup) :void
ProgramCellVIew
+ onCreate(Context) :void
+ setData(int, T) :void
구현객체
4.3 AdapterView Template(3)-Practice
Vector<ProgramData> list = …
ListCellViewAdapter adapter = new ListCellViewAdapter<ProgramData>(ProgramCellView.class, list);
mListView.setAdapter(adapter);
27.
Q&A
XML기반의 설정코드 간결화
- Preference는 CheckBox와 Sub Title이 대부분이다. 형태가 다양하지 않아서 모듈화가 쉽다.
- XML에 Preference Key,초기 값, 클릭 tag, 클릭 시 수행할 Action등을 처리하고 이를 위한 Framework를 정의.
4.4 XML과 Layout을 통한 간결화(1)
5.Data Transfer &Practices
Intent,Bundle의 Key-Value요소를 자동화
-Key 정의와 put,get을 자동화 Uri를 객체 맵핑 - host 및 파라메터를 로직 코드에서 찾지 말라 Application Storage를 활용하라 **전달 요소의 해석(파싱은)은 사용하는 곳에서…
30.
Intent와 extraBundle
-Intent의put,get 파라메터는 extraBunde에 저장됨.
-Activity 내에서 전달될 값들은 Annotation하여 식별 가능
-BundleMapper.toBundle()/fromBundle()등으로 간략화 가능
5.1 Intent Broadcast와 Intent Bundle
Broadcast VS Local Broadcast
-Broadcast는 단말에 따라서 전달시간의 편차 크고 보안 문제도 발생할 수 있다.
-앱 내에서는 Local Broadcast를 사용하는 것이 답이다. final String EXTRA_ID = “id”; final String EXTRA_MYLIST = “mylist”; String mId; boolean myList; … Intent intent = .. intent.putExtra(EXTRA_ID,mId); intent.putExtra(EXTRA_MYLIST,myList); … startActivity(intent)
31.
5.2 BundleMapper를 통한간결화
BundleMapper 객체
-Intent의 파라메터 또는 Bundle의 값을 Activity(또는 Container) 내의 멤버 변수에 읽고 쓸 수 있게 하는 도구이다=>키 맵핑 최소화
-@BundleField로 Annotation 된 변수의 이름 또는 name을 Key 값을 전달한다.
@BundleField(name=“id”) String mId; @BundleField(name=“mylist”) boolean myList … Intent intent = .. BundleMapper.toBundle(this,intent); startActivity(intent)
@BundleField(name=“id”)
String mKey;
@BundleField(name=“mylist”)
boolean isListValue;
…
void onCreate() {
Intent intent = getIntent()
BundleMapper.fromBundle(this,intent);
…
}
<그림>멤버 변수 값을 Intent 형태 전달
32.
Android에서 uri는? -Uri로 거의 모든 리소스를 표현 가능
-다른 앱 또는 Web과의 Interface는 Uri를 많이 사용
-Uri Host, Parameter 값으로 구조를 전달함
queryParameter()의 형태를 객체로 맵핑하여 코드를 단순화 할 필요가 있다
특히 웹 to App의 호출 Scheme이 기본적으로 사용되므로 잘 정의할 필요가 있다
UriMapper 객체를 사용하라.
5.3 Uri 의 Object 처리
deview://myprogram?version=1&sessionCode=101&action=add deview://note?version=1&title=NONE&attachement=clip.mov&content=…
33.
AppContext 저장소 -AppContext에 Object를 저장하기 위한 Key-Value Map을 사용한다.
-Intent 전달 시에 Serialize가 필요한 Object형태는 AppContext를 통한 전달이 효율적이다.
5.4 AppContext 통한 데이터 전달
ProgramData mData;
…
Intent intent = ..
AppContext.putValue(
MemoActivity.class,mData);
startActivity(intent)
…
void onCreate() {
Intent intent = getIntent()
ProgramData data = AppContext.getValue(MemoActivity.class,true)
…
}
MemoActivity.java
34.
6.Data Core &Practices
Table과 Cursor 처리의 자동화 XML/JSON API 처리 Framework을 활용하라
35.
SQLite의 Table Field1. NULL, INTEGER, REAL,TEXT 의 4가지 자료형만 존재 -객체를 통한 Table 정의가 용이 2. Cursor 를 통한 Table Read -Cursor를 직접 객체화 한다. 3. ContentValues를 통한 Table Write -객체에서 바로 ContentValue로 변환한다.
6.1 Table과 Cursor의 단순화(1)
DBTable.createTable (AppContext.getDB(),“program_cache_tbl”, ProgramData.class)
class ProgramData {
@DataField(attr=“”)
public String id;
@DataField(name=“name”)
public String name;
}
36.
CusorReader
-Cursor의 값을target Object 로 바로 변환해주는 객체.
6.1 Table과 Cursor의 단순화(2)
Cursor c = … Vector<ProgramData> list = CursorReader.readAll(c,ProgramData.class)
ContentValuesMapper -Class의 값을 Table에 쓰기 위해 ContentValues로 변환해 주는 객체
Vector<ProgramData> programList ; Vector<ContentValues> list = ContentMapper.toContetValues(programList);
37.
API-Data Object Model-XML/JSON 등으로 구성된 API를 서버에 접근해서 받아와서 파싱하고 적절한 자료구조로 직접 맵핑하는 구조가 필요하다. -GUI에서 데이터를 요청하고, GUI에 반영하는 코드를 단순화할 수 있다. - Java 의 Reflection, Annotation같은 Tool로 개발 가능하다. - Jackson/XStream 등의 Open 라이브러리 활용도 가능하다.
-Android의 자료구조에 최적화 되지는 않았음
-Android에 맞도록 최적화 한 라이브러리를 제작 추천
6.2 Data API Automation(1)
38.
6.2 Data APIAutomation(2)
Http Session
File
Input Stream
Default
DataProcessor
Data
Doc
Default Listener
UIProxy
Xml DataProcessor
JSON DataProcessor
Source
Processor
Sink