naver 오픈세미나 대구 (2014.08.01) - 오픈소스 라이브러리를 활용한 네이티브...
DESCRIPTION
오픈소스 라이브러리를 활용하여 안드로이드 네이티브 어플리케이션 작성시 도움이 되는 것들을 소개합니다.TRANSCRIPT
오픈소스 라이브러리를 활용한네이티브 어플리케이션에서의데이터 저장과 통신
추승우네이버 PWE개발랩
오늘 다루는 것
NATIVE
언제 네이티브 앱을 만들어야 할까요?
VS
언제 네이티브 앱을 만들어야 할까요?
VS
디바이스 제어 (카메라 등)가 필요하다
오프라인 사용이 필요하다
플랫폼별로 최적 UI를 만들고 싶다
애니메이션 사용량이 많다
포맷 변경이 갑자기/자주 일어나지 않는다
내용 포맷 변경이 자주 있다
다양한 플랫폼에서 사용하고 싶다
심사를 기다리지 않고 업데이트해야 한다
네이티브앱 하이브리드앱
일부분만 웹뷰를 사용하여 만들기도 합니다
• 공지사항, 고객문의 등의 여러 앱에서 사용하는 공
통기능을 웹뷰로 만드는 경우
• 컨텐츠의 자유도가 너무 높아서 웹뷰를 사용하여
내용을 구현하는 경우 (E-book 등)
• 지불결제 서비스 등 타사 연동을 위한 경우
비행기 안에서 스마트폰 써 보셨나요?
많은 모바일 어플리케이션은
네트워크가 아주 불안정한 상황이거나
심지어 오프라인일때도
동작할 수 있도록 설계됩니다.
네이버 메일
잘못된 예
개인화도구 (할일, 메일, 캘린더, 메모, 녹음기…)나
유틸리티, 게임류의 어플리케이션은
가급적 오프라인모드에서도 동작해야 합니다.
Demo App “기획서”
…
영화목록 영화상세
여러분의 기획자가 이런걸 만들어달라고 합니다
• 최근 개봉한 순서대로 영화를 보여주세요.
• 영화 상세정보도 보여주세요.
• 오프라인 모드에서도 최근 데이터 기반으로 보여주세요.
• 앱 실행중 데이터에 번동이 있으면 바꿔 주세요.
• 데이터를 덜썼으면 좋겠어요
• 배터리 적게 썼으면 좋겠어요
• “ CGV앱”처럼 만들어주세요.
일반적인 네이티브 앱
View LogicRequest
Response
SQLite
Event
3G/LTEWiFi
서버
화살표가 있는 구간에서 모두 해결해야 할 문제가 하나 이상씩 있습니다.
모바일 네트워크
• 분당에서 대구까지 KTX를 타고 이동했다. 과연 IP가 바뀔까?
• 단말기 전원을 껐다 켰다. IP가 바뀔까?
• 미국에 도착하여 비행기에서 내리자마자 로밍을 켰다. 미국에 할당된 IP를 받아올까?
• 데이터통신중에 전화가 걸려오면 통신중인 세션이 끊어질까?
(3G Fallback)
No
Maybe
No
No
이런 질문 해 보셨나요?
LTE 모바일 네트워크
단말기 기지국 패킷게이트웨이
터널관리
인증
핸드오버앵커PPP Tunnel
UE : User EquipmenteNodeB : Evolved Node BS-GW : Servicing Gateway
PDN-GW : Packet Data Network GWMME : Mobile Management EntityHSS : Home Subscriber Server
PCRF : Policy and Charging Rule FunctionePDG : Evolved Packet Data Gateway
바퀴를 새로 발명할 필요는 없습니다.
오픈소스 라이브러리를 최대한 활용하면
안정적이면서도 빠른 네이티브 앱 개발이 가능합니다.
View LogicRequest
Response
SQLite
Event
3G/LTEWiFi
서버
HTTP 통신 구간
서버로 향하는 통신을 수행하고,그 결과를 사용하여 자바 객체를 생성하는 부분필요시 이미지 다운로드
한국 무선 통계
0
50
100
150
LTE 3G WIFI
0
10
20
30
40
50
LTE 3G WIFI
DN (Mbps) UP (Mbps)
자료: 벤치비, 미래창조과학부
ms
Mbps
지연시간 (Latency)
전송속도
0
10
20
30
40
50
60
CDMA
3G
LTE
WIBRO
백만명 국내 무선통신 사용자 현황
“30%의 사용자는 아직도 3G망을 사용 중”
믿을만하지 못한 무선 네트워크 환경 + 믿을만하지 못한 HTTP 라이브러리 = ?!
안드로이드는 기본적으로 두 가지의 HTTP 클라이언트를 제공합니다.
Apache HTTP Client HttpURLConnection
• 아파치에서 만든 HTTP 클라이언트.
• 최신 버전으로 제공은 안됨.
• 사용하기 복잡하고 무거움.
• 안드로이드 버전별로 약간씩 다른 행동.
• 버그가 많음.
둘다 Deserialization을 안해주므로, 좀 더 쓰기 편리한써드파티 오픈소스 라이브러리도 많이 있습니다.
Volley OkHttp+Retrofit
• 이미지 처리에 특히 장점을 가지고 있음
• Google IO 에서 발표되었으나, follow up이
원활하지 않음.
• NIO기반으로 비교적 빠른 성능
• SPDY 지원
• Google 공식 컨퍼런스 등에서 사용된
적이 없음.
주: 기타 많은 라이브러리가 있습니다. HelloWorld 블로그에 있는 비교 포스트도 참고하세요.
HTTP 라이브러리 3G 성능측정
0
2
4
6
8
10
12
14
16
시나리오 1 시나리오 2 시나리오 3
AsyncTask Volley Retrofit + OkHttp
(초)
KT 3G / LG Nexus 5 / HTTP+SSL시나리오 1 : 목록 API 5회시나리오 2 : 목록 API 5회 + 상세 API 30회시나리오 3 : 목록 API 30회 + 상세 API 100회
서버를 확인하세요 : Gzip, TCP slow start (keepalive)
0
100
200
300
400
500
600
700
800
900
Non-gzip Gzip
kb API 응답 크기 TCP 성능 (Slow start, congestion avoidance)
서버를 확인하세요 : SPDY
자료: SIGCOMM 2013, “Towards a SPDY’ier Mobile Web?”• Nginx : http://nginx.org/en/docs/http/ngx_http_spdy_module.html• Apache : https://code.google.com/p/mod-spdy/
SPDY는 보다 적은 수의 컨넥션을 활용하여 더 많은 데이터를 처리합니다.다량의 API 콜이 발생하는 경우, API 수정 없이도 더 빨라집니다.
Retrofit http://square.github.io/retrofit/
서비스 선언Public interface MovieListService {
@GET(“/movielist”)List<MovieList> movieList();@GET(“/moviedetail/{id}”)MovieDetail movieDetail(@Path("id") int id);
}
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint("https://.../movielistdemo").build();
MovieListService service = restAdapter.create(MovieListService.class);
서비스 호출List<MovieList> movieList = service.movieList();
서비스 호출 (비동기)public interface MovieListService {
...@GET(“/moviedetail/{id}”)void movieDetail(@Path("id") int id, Callback<MovieDetail> callback);
}
service.movieDetail();
Picasso http://square.github.io/picasso/
Picasso.with(context).load(url).resize(50, 50) // 메모리 사용 절약을 위해 리사이즈.centerCrop() // 가운데로 크롭.setIndicatorsEnabled(true) // 캐시 모드 표시.placeholder(R.drawable.image_placeholder) // 다운받아지기 전에 보여줄 리소스.error(R.drawable.image_error) // 오류발생시 보여줄 리소스.into(view);
View LogicRequest
Response
SQLite
Event
3G/LTEWiFi
서버
데이터 저장
받아온 데이터를 로컬에 저장하고필요시 다시 불러올 수 있는 로직
난 데이터를 저장하고 불러들이고 싶었을 뿐인데…
android.database.sqlite.SQLiteException: database is lockedandroid.database.sqlite.SQLiteException: unable to open database file...
SQLite를 잘 사용하는 것은 절대 쉽지 않습니다.
대부분의 모바일 앱에서 필요한 것은 복잡한 SQL이 아니라,인스턴스를 저장했다 불러내는 기능입니다…
GreenDAO
TestDaoGenerator.javapublic static void main(String args[]) throws Exception {
Schema schema = new Schema(3, "me.sungwoo.listdemo.dao");Entity movieList = schema.addEntity(“MovieList");movieList.addIdProperty();movieList.addStringProperty("title");movieList.addStringProperty("description");new DaoGenerator().generateAll(schema, args[0]);
}
Generator 프로젝트를 만들어 준다.
build.gradleapply plugin: 'application'apply plugin: 'java'
mainClassName = 'me.sungwoo.listdemo.daogenerator.TestDaoGenerator'outputDir = '../app/src/main/java-gen'
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])compile 'de.greenrobot:DaoGenerator:1.3.0'
}
task createDocs {def docs = file(outputDir)docs.mkdirs()
}run {
args outputDir}
id title description
1
2
3
http://greendao-orm.com
GreenDAO
DaoSession 생성DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this,
“moviedb", null);SQLiteDatabase db = helper.getWritableDatabase();DaoMaster daoMaster = new DaoMaster(db);daoSession = daoMaster.newSession();
그냥 사용하면 끝!
자료 조회 (Select)MovieListDao movieListDao = daoSession.getMovieListDao();MovieList movies = listDao.queryBuilder()
.where(MovieListDao.Properties.Id.eq(id))
.orderDesc(MovieListDao.Properties.Id)
.list();
자료 삽입 (Insert)MovieList item = new MovieList(null, "은하수를 여행하는 히치하이커", “42");
movieListDao.insert(movieList);
자료 삭제 (Delete)movieListDao.deleteByKey(id);
SQLite Tip
WAL 사용SQLiteDatabase db = SQLiteDatabase.openDatabase(“db", cursorFactory,SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);db.enableWriteAheadLogging();
• API 16 부터 지원
• 쓰기를 모아서 수행하여 Lock 시간을 감소
• E_SQLITE_LOCKED 볼 일을 줄여줍니다!
View LogicRequest
Response
SQLite
Event
3G/LTEWiFi
서버
이벤트 처리
언제 완료될 지 모르는 작업들이 끝났을 때어느 쓰레드에서 무엇을 갱신해줘야 할까?
Event Bus의 활용
목록View
상세정보View
Logic
• 비동기로 완료된 작업이 어디로 값을 돌려줘야 할까?
• 데이터가 갱신되었는데 callback을 빼먹어서 버그 발생?
Event bus
Internet
새로운 데이터데이터 갱신 요청
“비동기적으로 연속적으로 처리되어야 할 작업들을
‘이벤트’로 정의하여 보다 부드럽게 구현”
Otto http://square.github.io/otto/
공용 이벤트 버스 생성bus = new Bus(); // 일반 이벤트 버스mainBus = new Bus(ThreadEnforcer.MAIN); // Main thread로 불러지는 버스
이벤트 수신자 (Subscriber)@Subscribe public void updateMovieList(MovieList list) {
// Do something}
bus.register(this);
이벤트 던지기bus.post(new MovieList(1, "Hi", "There"));
예제 앱 오픈소스 스택
View LogicRequest
Response
SQLite
Event
3G/LTEWiFi
서버
Android SDK
RetroFit
OkHttpOttoGreenDAO
SQLite
User View Logic
Otto
GreenDAO
RetroFit
One more thing : iOS
iOS용 라이브러리 몇 가지를 소개합니다
HTTP 통신
• AFNetworking (OkHttp + Picasso + Retrofit)
• FastImageCache (Picasso)
Event Delivery
• NSNotification
• Tolo (otto)
DB Storage
• Core Data
• 암호화가 필요한 경우 : SQLCipher
DEMO
Q&A
감사합니다