Thumbnail을 가져와야 하니, 보통 위 메소드 안에서 Thumbnail을 가져오기 위해, AsyncTask를 상속받은 쓰레드로 처리를 하는 것이 일반적입니다. 이 상황은 쓰레드를 많이 생성하게 됩니다..
위의 경우에 RejectedExecutionException 이 발생할 수 있습니다.. 안드로이드는 내부적으로 java.util.concurrent 패키지의 ExecutorService를 Thread 디스패칭에 사용하고 있습니다. 따라서, 요 문제는 아래의 ExecutorService가 처리해야 하는 AsyncTask의 POOL_SIZE가 순간적으로 넘어서고, 이 경우에 AsyncTask가 풀에 들어갈 수 없어서 발생하는 익셉션입니다. 위 문제는 빈번하게 발생하지 않을 것 같지만, 게임이라던지 쓰레드가 많이 필요한 작업을 하다 보면 발생할 수 있습니다..
아래는 Android 플랫폼에서 기본적으로 가지고 있는 AsyncTask의 정책값입니다.
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = 10;
private static final int KEEP_ALIVE = 10;
따라서, 위 문제는 하나의 쓰레드로 30개의 이미지를 가져오는 형태로 살짝 바꾸면 해결이 됩니다. 당근 성능과 안전성의 트레이드 오프라고 할 수 있겠습니다..
위에서 간단하게 RejectedExecutionException을 피해갈 수 있는 방안에 대해서 살펴보았습니다..
위에서 고려한 사진의 Thumbnail에 대한 예로, 한번 더 고민을 해 보면, 만약에 30개를 가져오는 쓰레드를 getView()외에서 처리를 한다면, 지금 보고 있는 화면에서 사진이 안 보일 겁니다.. 왜냐하면, getView()에서 처리를 하지 않았기 때문에 빈 사진만 보이겠죠.
그래서, 위 가정대로, 사진이 많아서 페이징을 해야하고 Thumbnail을 보여준다면, 사진을 가져오는 첫 페이지에서는 getView()에서 AsyncTask를 불러서 사진을 가져오고, 두 번째 페이지 부터는 데이터를 가져와서 Adapter에 바인딩하는 쓰레드가 30개의 사진을 처리하는 쓰레드를 다시 부르는 형태로 구현을 하는 것이 좋을 것 같습니다..
안드로이드에서는 메세지를 보여주고 사라지는 용도로 Toast를 빈번하게 사용하고 있습니다.
하지만, 아쉬운 점이 하나 있다면, duration을 설정할 수 없습니다.
그래서, 간단하게 duration을 변경하는 방법으로, Toast의 show()를 쓰레드로 원하는 시간 만큼 계속 보여주면 쉽게 해결할 수 있습니다.
간단하게, 안드로이드 Toast 클래스에서 제공하는 SHORT과 LONG의 기본 시간값입니다..
private static final int LONG_DELAY = 3500; // 3.5 seconds
private static final int SHORT_DELAY = 2000; // 2 seconds
아래는 CountDownTimer를 이용해서 총 4초동안, 1초씩 줄어들면서 Toast의 show() 메소드를 호출해서, 총 6초(Toast.LENGTH_SHORT이 duration 이니)동안 메세지를 보여주는 코드입니다..
final Toast toast = Toast.makeText(context(), getString(R.string.login_error),Toast.LENGTH_SHORT);
toast.show();
new CountDownTimer(4000, 1000) {
public void onTick(long millisUntilFinished) {toast.show();}
public void onFinish() {toast.show();}
}.start();
올해가 벌써 한 달이 가까워지게 지나가고 있다.
세월은 엄청 빠르게 지나가고 있다.. 특히, 내가 나이가 먹으니 더 느껴진다.. ^^;;
작년에 대한 포스트 모텀이지만, 작년을 얘기하려면 제 작년에 N사를 그만두면서 느꼈던 시간의 아까움에 대해서 얘기를 해봐야겠다..
시간,, 정말 중요한 거 같다.. 경력이 주로 N사다 보니 참 편하게 회사에 다녔던 거 같다..
그리고 정말로 나오기 전에 롤 모델로 삼고 싶은 CTO님을 만나게 된 것이 행운이었다.. 어찌 보면 아이러니 하지만, 그분을 보면서 시간의 아까움과 뭔가를 해봐야겠다라는 생각을 강렬하게 받았기 때문이다..
그래서 결국 N사를 퇴사하고 비교적 고행(?)길로 들어서게 되었다.. ^^
그래서, 작년에 한 일에 대해서 얼추 얘기해 보자면..
1. 전 직장에서 퇴사하다..
잘한 결정이고 후회는 없다..
아키텍처링과 백엔드의 경험은 매우 좋았다.. 그리고, 당근 좋은 분들을 알게 된 게 가장 알찬 거겠지.
2. 카산드라 완벽 가이드를 번역하다.
개인적으로 작년에 최대의 산출물이라고 생각한다. 그 이유는 번역을 하면서 오랜만에 집중해서 공부를 해본거 같다.. 선배 형하고 같이 진행을 하면서, 서로 바쁜 업무로 인해서 쉽지는 않았지만, 정말 편집자(한동훈님)를 잘 만나서 매우 만족을 한다.. 실제 업무에서 카산드라를 사용하고 있었고, 번역하면서 카산드라에 대한 경험치를 많이 터득할 수 있었다.
3. 안드로이드 앱을 런칭하다.
전 회사에서 아이폰 앱을 런칭하려고 시도했으나, 매우 힘들게 진행되는 것을 보고 답답했었다.
그래서, 지금 회사에 TO가 모바일 쪽이었고, 커리어에 대한 고민은 하긴 했지만, 우선 고하기로 했다.
그리고, 작년에 첫 타블릿 앱이 출시가 되었다. 처음 개발한 앱이라서 힘도 들긴 했지만, 그럭저럭 좋은 앱을 개발한 거 같아서 좋다.. 작년부터 지금까지 새로운 안드로이드 앱을 준비하고 있다.. 이 앱은 우여곡절이 좀 있다.. 일 하기가 매우 힘들었고, 난항도 많았다.. 그래도, 거의 개발이 완료가 되서 출시를 목전에 두고 있다..
이 내용은, 별 감정이 개입되지 않은 일련의 업무의 타임라인이라고 할 수 있겠다.
이제, 제 작년부터 준비를 했던, 실리콘 밸리에서의 개발자로서의 삶을 목전에 두고 있다.
어찌보면 영어도 못 하면서 실리콘 밸리에 있는 회사를 들어갔으니, 나름 성공적으로도 보일 수 있겠다.
개인적으로, 미국에 있었던 반년은 매우 힘들었다. 정말 몰랐으니 덥썩 덤벼든 거였다.. 가족이 있다보니, 가족과 떨어져 있는 것이 이렇게 힘들다는 것을 뼈져리게 느끼게 되었다.
앞으로 누구한테도 가족과 떨어져서 일을 오래해야 하는 형태는 추천하지 않겠다..
그리고, 영어가 부족하다 보니, 일할때 문제가 생기곤 한다. 소프트웨어 개발은 다양한 컨텍스트 상황에서 어떻게 처리를 해야 하는지 명확하게 짚어야 하고, 결정된 내용을 잘 구현해야 좋은 소프트웨어를 개발할 수 있겠다.
그런데, 명확하게 이해를 하지 못하는게 간혹 있기도 하다.. 다행이 나는 옆에서 일하는 개발자가 영어를 잘해서 통역도 해준다.. 땡큐.. ^^
영어는 생존이 걸려 있기 때문에 열심히 해야될 필요가 있겠지만서도 개발과 영어 둘 다 집중할 시간에 대한 선택을 한다면 또 다시 개발을 잘하기 위한 시간에 투자를 할것 같다..
한국에서는 실리콘 밸리가 개발자들의 천국이라고 말하고 있다. 과연 모가 개발자들에게 어필할 수 있기에 천국이라는 표현을 과감하게 썼을까 하는 고민을 해 본다..
천국이라.. 너무 과분한 표현 아닌가? 과분을 떠나 단지 미국에서 일하는 것에 대한 환상 아닐까?
요즘의 국내에서의 개발자들에 대한 대우도 좋아지고, 인식도 매우 좋다. 기술력도 그렇게 나쁘지 않다고 생각한다.
다만, 국내의 유수의 기업에서는 소스에 대한 공개와 유지에 대한 비용문제에 대해서 좋지 않은 견해를 가지고 있는 회사들이 많고, 회사 내부에서도 기득권에 대한 유지를 위해서 소스공개를 터부시하는 문화도 한 목 하기 떄문일 것이라 생각한다..
실리콘 밸리에서 개발자로서의 삶을 살아가기 위해서, 다시금 맘 가짐을 잡자면, 잘 할수 있는것에 집중을 하자이다..
단지 수요에 비해서 공급이 못 따라가는 것이라는 느낌이라서, 경쟁력을 가지는게 현명할 대처일 수 있다는 마지막 소견이라는.. ^^
Facebook은 정말 플랫폼 회사라고 할 수 있는 다양한 SDK를 지원하고 있고, 그 중에 안드로이드에서 Facebook을 쉽게 연동할 수 있는 SDK가 있습니다.. 보통 SDK라고 하면, 전통적인 관념에서 보자면, 소트프웨어를 개발하가 위해서 지원하는 툴킷을 포함한 라이브러리(?)라고 정의할 수 있겠습니다..
그런데, Facebook SDK를 받아서 사용해 보면, 라이브러리는 아니지만, 그렇다고 해서 SDK라고 봐야 하는지도 약간은 의문인데.. 형태는 프레임웍의 모습을 띄고 있습니다.. 흠, 모습이 좀 애매해서, 그냥 SDK라고 봐야 하나 봅니다..
서두가 너무 길었네요.. ^^;;
제가 안드로이드에서 Facebook을 연동하면서 이슈가 될 만한 것중에 2가지를 골라봤습니다..
1. 인증창이 안뜨는 경우가 종종 발생한다..
제가 2.2와 2.3버전에서 테스트를 해 봤는데, 에뮬레이터는 잘 동작합니다..
하지만, 폰에 설치를 해보니, 되는 폰도 있고 아닌 것도 있습니다..
그래서, 인증창을 띄울때 기존의 예제에서 조금 더 추가해줘야 할 필요가 있습니다.
facebook.authorize(this, new String[] { "email", "publish_checkins" },
new DialogListener() {
@Override
public void onComplete(Bundle values) {}
@Override
public void onFacebookError(FacebookError error) {}
@Override
public void onError(DialogError e) {}
@Override
public void onCancel() {}
}
);
- 위의 코드로 인증창이 안뜨는 문제가 해결된 코드..
facebook.authorize(this, Facebook.FORCE_DIALOG_AUTH, new String[] { "email", "publish_checkins" },
new DialogListener() {
@Override
public void onComplete(Bundle values) {}
@Override
public void onFacebookError(FacebookError error) {}
@Override
public void onError(DialogError e) {}
@Override
public void onCancel() {}
}
);
2. Facebook accessToken의 캐싱타임..
- 요 문제는 기본적으로 accessToken의 캐싱 타임이 하루로 설정되어 있기 때문에 발생할 수 있습니다. https://github.com/facebook/facebook-android-sdk/blob/master/facebook/src/com/facebook/android/Facebook.java 소스의 대략 91번째 줄이 accessToken의 캐싱타임입니다..
코드를 살짝 보니, 두둥 final private long REFRESH_TOKEN_BARRIER = 24L * 60L * 60L * 1000L; <-- 수정도 보지도 마라라는 코드.. ^^;;
흠, 그래서 입맛에 맞게 accessToken의 캐싱 타임을 줄이려면, Facebook SDK의 REFRESH_TOKEN_BARRIER 값을 변경해야 합니다..
Android WebView가 제공하는 getUrl() 메쏘드는 WebView를 통해서 가져온 웹 페이지의 URL을 넘겨줍니다.
대체로 getUrl() 메쏘드는 redirect된 사이트의 url을 가져옵니다.. 하지만, 간혹 redirect 하는 페이지에서 현재 사이트이 url이 아닌, redirect 전의 url을 가져오는 경우가 있습니다..
그래서, 위와 같은 문제를 해결하기 위한 방안으로, android webkit의 WebViewClient를 상속받아서 WebView의 페이지 로더로 바인딩을 해서 처리하면 해결할 수 있습니다..
* WebClient를 상속받은 클래스
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class OAuthWebClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@Override
public void onPageFinished(WebView view, String url) { // WebView의 페이지 로드가 완료되면 콜백의 형태로 이 메쏘드가 호출됩니다.. 좀 더 정확하게는 WebView가 이벤트 발생하는 경우 WebViewClient의 선언된 메쏘드들을 호출하고, 요 형태는 전형적인 옵저버 패턴의 모습입니다.
}
}
* WebView에서 위의 클래스를 사용하는 형태
- 아래 코드는 WebView에서 url이 바뀌는 것을 주기적으로 2초마다 모니터링하는 스켈레톤 코드의 형태이다.
webView.setWebViewClient(new OAuthWebClient());
Timer timer = new Timer();
TimerTask monitorThread = new TimerTask() {
@Override
public void run() {
if(webView == null || webView.getUrl() == null)
return;
// url이 현재 webView의 url이 아닐수 있기 때문에, 위에서 선언한 클래스의 onPageFinished() 메쏘드를 활용할 필요가 있다.
String url = webView.getUrl();
}
}
timer.schedule(monitorThread, 10* 1000, 2000); // 10초 후에, 매 2초마다 monitorThread를 실행
결론으로, WebView의 getUrl()메쏘드가 잘 동작하지만, 실제로 잘 못 가져오는 문제가 있기 때문에, 정확한 URL을 가져오기 위해서는 위의 WebViewClient를 상속한 OAuthWebClient같은 클래스를 만들어서, 좀 더 정확하게 의도한 바를 오버라이딩을 통해서 구현할 수 있을 것이다.
아래 내용은 제가 테스트한 내용이 아니라, 경험을 기반으로 제가 생각하는 고성능의 서비스를 위한 아키텍처링에 대한 내용입니다. 그리고, 아래 내용은 앱<->API 서버 간의 성능향상을 위한 방안에 대한 내용입니다.
요즘 상당히 많은 앱들이 네트웍으로 데이터를 전송받아서 랜더링하고, 유저가 만들어낸 데이터를 전송하기도 합니다. 그래서, 네트웍으로 데이터를 주고 받는 앱들은 서버(보통 웹서버)와의 통신에서 JSON을 표준(많이 사용하는 추세) 프로토콜처럼 사용하고 있습니다. JSON을 사용하는 아키텍처가 가지고 있는 성능저하 요소를 살펴보면, 아래의 목록을 예상할 수 있습니다.
- JSON의 사용은 파싱에 드는 비용, 데이터 사이즈로 인한 전송(3G 대비)속도 저하가 예상이 됩니다..
- HTTP/HTTPS 프로토콜을 사용하는 서버(웹 서버)를 사용해서, 연결과 데이터 전송과 수신에 오버헤드(HTTP 프로토콜의 헤더만 읽어봐도 이해가 되실 듯)가 발생합니다.
그래서, 위의 성능저하 요소를 걷어내고 고성능의 앱을 개발하기 위한 방법으로.. 아래의 방식을 고려할 필요가 있습니다.. 아래의 형태로 개발하게 되면, 개발 비용이 증가하는 단점이 있습니다.. 하지만, 네트웍을 많이 사용하는 앱(예로 카카오톡이나 채팅앱)이라면 연결기반의 프로토콜을 서버가 제공하고, 앱이 그 프로토콜을 사용한다면, 매번 연결하지 않고 네트웍으로 데이터를 보내고 받는 것이, 위의 비 연결지향의 프로토콜인 HTTP/HTTPS와는 비교할 수 없을 정도로 빠른것을 알게 될 것입니다..
- JSON 보다는 고 성능의 데이터 직렬화 라이브러리(MessagePack, Thrift, Google Protocol Buffers)를 사용한다.
- 소켓(SSL 적용) 서버(Netty 프레임윅 등으로 개발)로 연결지향 프로토콜 기반에서 데이터를 처리한다. 이 방식의 경우에는 소켓 서버에서 클라이언트의 idle time을 적절하게 계산해서 주기적으로 클라이언트의 소켓을 제거해 주는 로직이 필요합니다.. 이 로직이 없을 경우, file descriptor가 부족해 지겠죠.. ^^
당장은, 필요하다고 느끼지 못하거나, 너무 오버한다고 생각할 수 있으나, 기본적으로 유저가 많은 포털의 앱이나, 이미 많은 유저가 사용하는 앱들은 프로토콜과 데이터 형식만 바꿔도 상당한 성능향상을 가져올 수 있을 것이라 생각합니다.. ^^
이클립스에서 문법이 전혀 틀리지 않았는데..
selector.xml이 layout에서 전혀 보이지 않는 문제가 종종 발생을 합니다..
몬가 살펴보니, Error Log를 보라고 해서, 살펴보니 아래와 같네요..
org.xmlpull.v1.XmlPullParserException: Binary XML file line #3: <item> tag requires a 'drawable' attribute or child tag defining a drawable
................
....
..
간단한 selector인데 흠.. drawable attribute도 있구요..
흠... 아무리 해도 안되네요.. ^^;;
그래서, 이클립스를 다시 재시작을 했습니다.. 잘됩니다..
젠장, 그래서 결론은 문제가 없어 보이는데, 에러가 발생하면, 재시작.. 재시작이 중요한 해결책이 될 수 있겠네요.. ^^
Dialog는 안드로이드에서 자주 사용되는 UI 컴퍼넌트이지요..
그런데, Dialog를 show()하고 종료하기 위해서, cancel(), dismiss()를 사용할 수 있는데요..
API 문서에서는 아래와 같이 설명을 하고 있습니다.. 제가 UI쪽은 거의 안해봐서 그런가? 동작하는게 똑 같아 보입니다..
아래 dismiss()메소드는 스크린에서 dialog를 제거하는데 쓰레드 세이프 하다네요..
Dismiss this dialog, removing it from the screen. This method can be invoked safely from any thread. Note that you should not override this method to do cleanup when the dialog is dismissed, instead implement that inonStop().
대충 예제 코드만 보면, 버튼의 클릭은 trackEvent, Activity를 로딩해서 데이터를 가져오는 형태는 trackPageView 메소드를 호출해서 통계자료로 사용하는 것으로 보인다.. 그리고, 코드는 일정시간이 지나면 Cron 잡처럼 디스패칭해서 데이터를 서버(Google Analytics)로 전송하는 형태라는 것을 알려주고 있다.
흠,, 그래도 도대체 어떻게 구현했는지가 궁금했다.. 그래서, 살짝 까본 결과는 아래와 같다.
* GoogleAnalyticsTracker는 static 인스턴스로 전형적인 싱클톤 패턴의 형태를 띠고 있다.
* 예제의 startSession 메소드를 호출하게 되면
** 이벤트를 저장할 데이터베이스를 생성한다
** 네트웍으로 처리할 디스패처를 생성한다..
** 디스패처의 콜백을 받을넘을 생성한다..
** 네트웍 연결관리하는 매니저를 생성하고..
** 안드로이드의 Handler를 하나 생성한다.. 이넘의 용도는 Timer의 schedule메소드와 비슷하게 일정시간 뒤에 등록한 Handler의 메소드를 실행한다..
* 예제의 trackEvent를 호출하면..
** 이벤트 객체를 만들어서, 위의 Handler객체의 postDelayed메소드를 사용해서 디스패처를 구동한다.
흠, 위 과정이 Google Analytics for Android가 서버에 통계데이터를 리포팅하는 러프한 과정이다.
그 중에서도 디스패처로 NetworkDispater 클래스(내부적으로 아파치 HTTP 라이브러리 사용)를 사용하고 있는데, 틀만 살펴보면 아래와 같다..
class NetworkDispatcher implements Dispatcher
{
private static final String GOOGLE_ANALYTICS_HOST_NAME = "www.google-analytics.com";
private static final int GOOGLE_ANALYTICS_HOST_PORT = 80;
private static final int MAX_GET_LENGTH = 2036; // 2048도 아닌 2036의 사이즈는 왜?? 흠.. 궁금하다..
private static final int MAX_POST_LENGTH = 8192;
private static final String USER_AGENT_TEMPLATE = "%s/%s (Linux; U; Android %s; %s-%s; %s Build/%s)";
private final String userAgent;
private static final int MAX_EVENTS_PER_PIPELINE = 30;
private static final int MAX_SEQUENTIAL_REQUESTS = 5;
private static final long MIN_RETRY_INTERVAL = 2L;
private final HttpHost googleAnalyticsHost;
private DispatcherThread dispatcherThread;
private boolean dryRun = false;
public NetworkDispatcher()
{
this("GoogleAnalytics", "1.4.2");
}
JSON 포맷으로 데이터를 주고 받는 서버나 클라이언트 혹은 앱을 개발하다 보면, 보내고 받은 데이터의 포맷이 맞는지 그리고 받은 데이터를 디버깅하기 위해서 포맷팅을 해서 가독성있게 바꾸는 작업을 빈번하게 하게 됩니다.. 이 때, 프로그램상에서 로그나 콘솔에 포맷팅을 해서 가독성있게 보여줄 수 있겠지만, 여간 불편한게 아니죠..
보통, 웹 서버를 통해서 JSON 데이터를 받게되면, 스트림으로 주~욱 받게 됩니다.. 그러면, byte[]로 받아서 String으로 변환을 해서 포맷팅을 하든, 아파치 HTTPClient같은 넘을 사용해서 결과로 String을 받아오든지 합니다..
결국, 다시 한번 String을 포맷팅을 해야 가독성이 생기게 됩니다.. 그래서, 받은 String 데이터를 Validate와 Formatting을 해주는 사이트를 찾아서 받은 String 데이터를 넣어서 포맷팅된 JSON으로 보게 되네요..
그래서, 유용한 사이트를 몇개 정리해 봅니다..
1. http://www.freeformatter.com/
지원하는 Formatter와 Validator는 아래와 같이 매우 다양합니다.. 매우 다양한 포맷을 지원하기 때문에 개발하면서 매우 유용한 사이트가 될 것 같습니다..
- JSON Formatter & Validator :
- HTML Formatter & Validator :
- XML Formatter :
- SQL Formatter :
- String Escaper :
- Url Encoder / Url Decoder :
- Base 64 Encoder / Base 64 Decoder :
- JavaScript Minifier - Online YUI Compressor for JavaScript :
- CSS Minifier - Online YUI Compressor for CSS :
- Message Digest :
2. http://jsonlint.com/
JSON Formatter와 Validator로 가장 유명할 것으로 생각이 드는 사이트 입니다.. 3. http://jsonformat.com/
JSON Formatter와 Validator를 지원하고 있고, 추가적으로 HTML Formatter도 지원하고 있네요..
Android 기반의 앱을 개발하다 보면, 해상도 문제가 골치 아프다..
특히, 태블릿을 지원하기 시작하는 허니콤이나, 모바일과 태블릿을 같이 지원하는 아이스크림까지 나온 상황에서는 말이다..
물론, 해상도에 적합하게 xml을 선언해서 개발하라고 하는 구글의 가이드(Supporting Multiple Screens)도 있지만, 다양한 해상도를 지원하기 위해서 /res/blahblah/layout.xml을 만들라고 하는것은.. 해상도에 맞춰 앱의 퀄리티를 유지하는 방향으로는 좋겠지만, 그 만큼 개발비용(iOS에 비해)을 증가시킬게 분명하다.. 물론, 이렇게 해서 태블릿도 하나의 앱에서 지원하면 좋겠지만, 개발해 보니, 이렇게 분리해서 태블릿의 장점을 녹여낼 수 있을까?라는 질문에는 회의적이다..
그래서, 개인적으로 도달한 답은 모바일 앱과 태블릿 앱을 분리해서 개발하는 게 좋을 듯 하다..
그럼, 각각의 앱을 개발하면서 각자(모바일, 태블릿)의 해상도는 어떻게 지원할 것인가? 에 대한 대답은 layout_weight으로 UI를 구성하는 것이다..
아래의 예제에서 빨간색으로 구성한 것들이 <LinearLayout>에서 각 UI가 차지하는 %를 숫자로 표현한 것이고, weightSum은 없으면 알아서 배열을 하지만, 아래의 예에서는 입력을 해 놓았다..
그리고, horizontal이든지 vertical이든지 비율로 크기를 맞추기 위해서는, 가로를 맞추기 위해서는 layout_width, 세로로 맞추기 위해서는 layout_height을 '0dp'로 입력을 해 두면 된다..
3. 해시키 만들고 등록하기..
3.1 해시키 만들기 : 아래의 명령을 통해서 해시키를 만든다..
> keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
3.2 만들어진 해시키를 Facebook에 등록한다.. Facebook Developer 페이지의 Step 5의 이미지를 보면 쉽게 확인할 수 있다.
- 이 테스트 자료는 자바환경에서 https://github.com/eishay/jvm-serializers 프로젝트에서 테스트한 자료입니다. - 테스트 결과중에 속도에 대한 차트만 첨부했습니다. 예전의 테스트 자료에서는 kryo가 protobuf보다 더 빠른 결과가 나왔었는데, 2011-07-13일 버전의 테스트 자료에서는 역전을 했네요.. ^^ 그리고, 위의 테스트 결과 위키에서의 답글(2011-10-27)을 보면, 테스트 결과에서는 kyro가 상당히 의미있는 결과를 보여주고 있네요.. 그리고 테스트 결과를 바탕으로 json 포맷을 지원하는 라이브러리 선택도 의미가 있을 것 같습니다.
- 이 테스트 자료는 상당히 방대한 자료에 대한 테스트를 진행했기 때문에 정말 유익합니다.. 꼭 자세히 살펴볼 필요가 있습니다.. 하지만, 최근(?)에 사용을 늘려가고 있는 MessagePack과 YAML에 대한 자료가 없는건 아쉽네요..
- 카산드라 0.7버전에서 MessagePack을 thrift의 대안으로 고려를 했었습니다.. 물론 카산드라 버전에서 MessagePack 라이브러리를 살펴볼 수 없기 때문에 채택이 안되었겠죠.. ^^ 카산드라의 JIRA CASSANDRA-1735에서 카산드라 프로젝트의 의장인 Jonathan Ellis의 코멘트를 보면, 의미가 없었다고 하네요..
Gary did some tests in CASSANDRA-1765 and found no significant advantage over Thrift. Given that, and our brief experience supporting a second rpc protocol (Avro in the 0.7 series), I don't think this is going anywhere.
- JIRA에서 살펴보면, 테스트 결과는 꽤 성능향상 이점(random read 15%, random write 21%)이 있어 보이긴 하네요.. 흠.. 위의 Jonathan Ellis의 코멘트가 사실이라면, 역시 테스트는 데이타에 따라 결과에 대한 차이가 상당한 것 같습니다..
Performance improvement available with this patch will be the following:
Reducing serialization cost and the data size
Increase throughput between clients and a Cassandra node
I have also measured the performance of MessagePack, from the viewpoints of reducing serialization cost and throughput. I will discuss details below.
== Reduction of serialization cost and the data size ==
(Summary)
MessagePack has proved to be better in reducing serialzation cost and the data size compared to other serialization libraries in the test below.
(Test environment)
I used "jvm-serializers" which is a well-known benchmark and compared performances with Protocol Buffers, Thrift, and Avro. Machine used for this benchmark has Core2 Duo 2GHz with 1GB RAM.
(Comments)
It may be better to compare serialization cost using objects with Cassandra like a Column object. But such objects and sizes vary by users, and is not suitable for comparing serialization cost of various data. According to the above result, the size of MessagePack's serialized data is slightly larger than Avro. But MessagePack has significantly low serialization cost compared to Avro and Thrift.
== Increasing throughput ==
(Summary)
I compared MessagePack based RPC of Cassandra to that of Thrift. Random read throughput of MessagePack based RPC is 15% higher than that of Thrift and random write throughput is 21% higher.
(Test environment)
In this evaluation, Cassandra node ran as a standalone on a machine with Core2 Duo 2GHz and 1GB RAM. Client programs ran on two machines both with Core2 Duo 2GHz and 1GB RAM. Client program was based on ring cache. It created 100 threads per a JVM on each machine and accesses to a Cassandra node with ring cache.
(Results)
Thrift based RPC part of Cassandra(read: 5,200 query/sec., write: 11,200 query/sec.)
MessagePack based RPC part of Cassandra (read: 6,000 query/sec., write: 13,600 query/sec.)
(Comments)
I measured the max throughput of random access (read/write) after 100 items (size of each item is small) were stored in the Cassandra node. The reason is because I wanted to make the state of CPU bottle neck for the Cassandra node. If the Cassandra node is the state of Disk IO bottle neck, I thought that I cannot properly evaluate max throughput of the RPC part.
I did not measure the amount of data transferred in network during the evaluation directly. But from the benchmark result of jvm-serializers, I believe that the amount of transferred data for MessagePack-based Cassandra would be reduced compared to that of Thrift.
Last night at the NYC Ruby hackfest, I got into a discussion about serializing data. Brian mentioned the Marshal library to me, which for some reason had completely escaped my attention until last night. He said it was wicked fast so we decided to run a quick benchmark comparison.
The test data is designed to roughly approximate what my stored classifier data will look like. The different methods we decided to benchmark were Marshal, json, eval, and yaml. With each one we took the in-memory object and serialized it and then read it back in. With eval we had to convert the object to ruby code to serialize it then run eval against that. Here are the results for 100 iterations on a 10k element array and a hash with 10k key/value pairs run on my Macbook Pro 2.4 GHz Core 2 Duo:
The order in which I tested them is pretty much the order in which they ranked for speed. Marshal was amazingly fast. JSON and eval came out roughly equal on the array with eval trailing quite a bit for the hash. Yaml was just slow as all hell. A note on the json: I used the 1.1.3 library which uses c to parse. I assume it would be quite a bit slower if I used the pure ruby implementation. Here's a gist of the benchmark code if you're curious and want to run it yourself.
If you're serializing user data, be super careful about using eval. It's probably best to avoid it completely. Finally, just for fun I took yaml out (it was too slow) and ran the benchmark again with 1k iterations:
안드로이드 2.3 부터인가? AsyncTask 기반의 쓰레드 프로그래밍을 해야 합니다.. 그러다가 자주는 아니지만 가끔 android.view.WindowLeaked 에러를 토하면서 앱이 죽을 때가 있는데, 이런 경우에는 별도 쓰레드(AsyncTask 같은)를 실행한 Activity가 onPuase나 onClose 상태가 되면서 finish되는 상태가 되고, 별도 쓰레드(UI 작업을 하는)가 아직 실행중인 상태에서 발생을 하게 됩니다.. 결국, 현재 Context를 AsyncTask에서 사용하고 있는데, Context가 사라저 버려서 발생을 합니다..
그래서, 간단한 해결책을 살펴보자..
Dialog류의 작업을 보통 AsyncTask로 많이 구동시키는데..
카산드라는 0.7 버전부터인가?? YAML 포맷의 파일을 설정파일로 사용하기 시작을 했다..
기존에는 YAML 파일은 JSON 포맷과 다른 또 다른 포맷으로만 알고 있었는데, 위키의 YAML 포맷에 대한 정의를 살펴보면, 사람이 쉽게 읽을 수 있는 데이터 직렬화 양식이라고 한다.. 흠 그래.. 쪼매 쉽게 읽히긴 한다..
아래에서 0.6 버전에서 사용했던 XML 포맷과 현재(1.0.2)에서 사용하고 있는 YAML 포맷을 살펴보자.. 어떤 설정이 더 가독성이 있을까? 라는 질문에 나는 XML 포맷이라고 답하겠다..
단순히 포맷만 보면, XML이 YAML 포맷에 비해서 비 효율적이고 파싱에 대한 비용도 많이 들겠다.. 하지만, 카산드라에서 아래의 용도는 클러스터/머신의 상황에 맞게 카산드라가 잘 돌게 하기 위한 설정이다.. 설정이라고 하면, 포맷에 맞춰서 설정한 값의 가독성이 매우 중요한 포인트라고 생각한다. 그런 면에서 나는 꼭 설정에 XML을 사용할 필요는 없겠지만, 가급적이면 YAML보다 쉽고(비교적 쉽게 느껴지는 주관) 가독성이 좋은 XML을 사용해 줬으면 하지만, 지금은 YAML 포맷이니.. YAML 포맷을 숙지하고 사용해야 겠지만, 아쉬운 느낌이다.. 아.. XML 포맷이 좋아지다니... ㅋㅋㅋ
The primary difference between Cassandra and Hadoop is that Cassandra
targets real-time/operational data, while Hadoop has been designed for
batch-based analytic work.
There are many different technical differences between Cassandra and
Hadoop, including Cassandra’s underlying data structure (based on
Google’s Bigtable), its fault-tolerant, peer-to-peer architecture,
multi-data center capabilities, tunable data consistency, all nodes
being the same (no concept of a namenode, etc.) and much more.
How does Cassandra differ from HBase?
HBase is an open-source, column-oriented data store modeled after
Google Bigtable, and is designed to offer Bigtable-like capabilities on
top of data stored in Hadoop. However, while HBase shared the Bigtable
design with Cassandra, its foundational architecture is much different.
A Cassandra cluster is much easier to setup and configure than a
comparable HBase cluster. HBase’s reliance on the Hadoop namenode
equates to there being a single point of failure in HBase, whereas with
Cassandra, because all nodes are the same, there is no such issue.
In internal performance tests conducted at DataStax (using the Yahoo
Cloud Serving Benchmark – YCSB), Cassandra offered literally 5X better
performance in writes and 4X better performance on reads than HBase.
How does Cassandra differ from MongoDB?
MongoDB is a document-oriented database that is built upon a
master-slave/sharding architecture. MongoDB is designed to store/manage
collections of JSON-styled documents.
By contrast, Cassandra uses a peer-to-peer, write/read-anywhere
styled architecture that is based on a combination of Google BigTable
and Amazon Dynamo. This allows Cassandra to avoid the various
complications and pitfalls of master/slave and sharding architectures.
Moreover, Cassandra offers linear performance increases as new nodes are
added to a cluster, scales to terabyte-petabyte data volumes, and has
no single point of failure.
모바일 애플리케이션들은 대체로 Http보다는 보안 이슈로 Https를 사용합니다..
안드로이드의 Http/Https 래퍼는 Apache HTTP Client와 Java의 HttpUrlConnection(HttpsURLConnection) 2 가지가 있습니다. 공식 블로그에서는 진저브레드(Gingerbread) 이상에서는 HttpURLConnection을 사용하기를 권장하고 있습니다. 하지만, 상당히 많은 앱에서 Apache HTTP Client를 사용하고 있을 것으로 생각이 듭니다.. 저 같은 경우에는, 양 쪽을 같이 혼용해서 사용하고 있습니다..
SSLSessionCache 클래스는 API 문서를 보시면 알 수 있습니다..
2개의 옵션을 제공하는데, 세션캐시를 특정위치에 저장할 수 있거나, 기본 위치에 저장하는 정도.. ^^;;
아래의 코드는 HttpClient를 생성해주는 메쏘드입니다.
빨간색 부분이 SSL에 SSLSessionCache를 사용하게 해 주는 코드입니다.. 흠..
public static synchronized HttpClient createHttpClient(Context c, int cTimeout, int sTimeout) {
// Use a session cache for SSL sockets
SSLSessionCache sessionCache = c == null ? null : new SSLSessionCache(c);
올해 작업했던 책이 드디어 출간을 합니다..
개인적으로 리서치 업무를 진행하면서 카산드라를 접하게 되었고, 업무에 카산드라를 적용해 보면서 많은 도움을 얻은 책을 번역하게 되서 너무 좋았습니다.. 그리고, 제가 좋아하는 형하고 같이 작업해서 아주 좋았습니다. 특히, 편집을 담당해 주신 한빛미디어의 한동훈님께서 너무 잘 정리를 해주셨습니다.. 비록, 카산드라 버전이 1.0.0의 정식버전이 런칭을 했지만, 책의 상당 부분이 0.6~0.7버전이 아닌 0.8 버전을 대상으로 작업을 해서 1.0.0을 적용하려는 분들께도 상당히 도움이 될 것으로 생각합니다..
Android에서 앱의 Activity Stack을 일정 숫자만큼 유지를 하는 클래스입니다..
이 클래스를 통해서 앱의 종료도 detect할 수 있습니다..
* ActivityManager클래스..
코드가 너무 간단해서 설명 생략..
import java.util.concurrent.LinkedBlockingQueue;
import android.app.Activity;
/**
* Activity Manager Class
* @author mcsong@gmail.com
*
*/
public class ActivityManager {
private static final int max = 13;
private static final int size =12;
private static LinkedBlockingQueue<Activity> queue = new LinkedBlockingQueue<Activity>(max);
private static final String CNAME = ActivityManager.class.getSimpleName();
public static void createActivity(Activity activity) {
if(activity == null)
return;
* 사용방법
- Activity 생성(onCreate 메소드에서)시에 createActivity()를 호출한다. 자연스럽게 size만큼 Activity Stack이 관리가 된다.
- 앱 종료 detect는 isRootActivity()로 확인을 하면 된다.. ture인 경우 각 Activity 클래스에서.. onBackPressed()를 Override해서 확인하면 된다.. 참고로, AbstractActivity 클래스를 만들어서 상속을 사용하면 코드가 깔끔해 지겠다..
- 앱을 종료하면서 clear()를 호출해서 Activity stack에 있는 Activity들을 다 날려주셔야 Activity 관리가 명확해 집니다.. ^^
* 안드로이드 activity의 동작형태는 android:launchMode="standard" 에서 잘 동작합니다.. ^^
- 파일 이름에 foobar 가 들어간 파일 찾기
find / -name "foobar" -print
- 특정 사용자(foobar) 소유의 파일을 찾기
find / -user foobar -print | more
- 최근 하루동안에 변경된 파일을 찾기
find / -ctime -1 -a -type f | xargs ls -l | more
- 오래된 파일(30일 이상 수정되지 않은 파일) 찾기
find / -mtime +30 -print | more
- 최근 30일안에 접근하지 않은 파일과 디렉터리를 별도의 파일로 만들기
find / ! ( -atime -30 -a ( -type d -o -type f ) ) | xargs ls -l > not_access.txt
- 하위 디렉터리로 내려가지 않고 현재 디렉터리에서만 검색하기
find . -prune ...
- 퍼미션이 777 인 파일 찾기
find / -perm 777 -print | xargs ls -l | more
- others 에게 쓰기(write) 권한이 있는 파일을 찾기
find / -perm -2 -print | xargs ls -l | more
- others 에게 쓰기(write) 권한이 있는 파일을 찾아 쓰기 권한을 없애기
find / -perm -2 -print | xargs chmod o-w
또는
find / -perm -2 -exec chmod o-w {} ; -print | xargs ls -l | more
- 사용자이름과 그룹이름이 없는 파일 찾기
find / ( -nouser -o -nogroup ) -print | more
- 빈 파일(크기가 0 인 파일) 찾기
find / -empty -print | more
또는
find / -size 0 -print | more
- 파일 크기가 100M 이상인 파일을 찾기
find / -size +102400k -print | xargs ls -hl
- 디렉터리만 찾기?
find . -type d ...
- root 권한으로 실행되는 파일 찾기
find / ( -user root -a -perm +4000 ) -print | xargs ls -l | more
- 다른 파일시스템은 검색하지 않기
find / -xdev ...
- 파일 이름에 공백이 들어간 파일 찾기
find / -name "* *" -print
- 숨겨진(hidden) 파일을 찾기
find / -name ".*" -print | more
- *.bak 파일을 찾아 지우기
find / -name "*.bak" -exec rm -rf {} ;
- *.bak 파일을 찾아 특정 디렉터리로 옮기기
mv `find . -name "*.bak"` /home/bak/