'전체'에 해당되는 글 298건

  1. Android RejectedExecutionException 처리.. 2012/01/31
  2. Android Toast duration 조정하기.. 2012/01/27
  3. 2011년에 대한 포스트 모텀.. 2012/01/22
  4. 안드로이드에서 Facebook 연동시에 발생할 수 있는 2가지 이슈.. 2012/01/21
  5. Android에서 String의 Base64 Utility 클래스.. 2012/01/14
  6. Android WebView에서 getUrl() 메소드 값이 현재 페이지가 아닌경우.. 2011/12/24
  7. 고성능의 앱을 위한 아키텍처링.. 2011/12/21
  8. Eclipse ADT에서 Layout의 selector xml의 이미지 버튼등이 안 보일때.. 2011/12/18
  9. Android의 Dialog의 cancel과 dismiss의 차이점.. 2011/12/07
  10. Google Analytics for Android.. 살펴보기. 2011/12/05
  11. JSON Validator/Formatter 사이트들.. 2011/11/29
  12. Android 다양한 해상도 지원하기.. 2011/11/28
  13. Android Facebook SDK 사용하기.. 2011/11/23
  14. 데이터 포맷별 성능 비교자료.. 2011/11/21
  15. android.view.WindowLeaked 문제에 대한 해결책.. 2011/11/16
  16. Java Magazine 11/12 2011 2011/11/16
  17. YAML 포맷을 편하게 다루기 위해서 필요한 것들.. 2011/11/12
  18. Cassandra에서 설정으로 사용하는 YAML 포맷에 대해서.. (1) 2011/11/12
  19. Android Oftener 프로젝트.. 2011/11/11
  20. Cassandra와 Hadoop, HBase, MongoDB와의 차이점.. 2011/11/08
  21. Ubuntu 11.10에 JDK 설치하기.. (3) 2011/11/05
  22. Android Apache Http Client의 SSL 성능개선을 위해서 SSLSessionCache 사용하기... 2011/11/03
  23. 카산드라 완벽 가이드 : 페이스북, 트위터를 지탱하는 기술, NoSQL (2) 2011/10/27
  24. Android에서 앱 Activity 관리 및 앱 종료 detect하기.. 2011/10/17
  25. Linux find 명령 option 2011/08/22
안드로이드는 기본적으로 프로그래밍 모델이 랜더링과 별도로 데이터를 가져오는 쓰레드를 AsyncTask를 상속받아서 Asynchronous하게 처리하게 끔 가이드를 하고 있습니다.. 참고로, 아래내용은 안드로이드 2.2 기반에서의 경험입니다. ^^

그래고, 많은 데이터를 가지고 오기 위해서 페이징을 합니다. 안드로이드는 하단에 spinner와 Loading과 같은 메세지가 표준처럼 사용되고 있죠.

사진에 대한 Thumbnail이 매우 많고, 30개씩 가져온다고 가정을 합니다.. 보통 ArrayAdapter나 ListAdapter를 상속받아서 Adapter 객체를 만들고, Adapter 객체의 getView()에서 랜더링을 위한 작업을 구현하게 됩니다.
@Override
public View getView(int position, View cView, ViewGroup parent) {
}

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();

또 다른 방법으로 https://github.com/quiqueqs/Toast-Expander/blob/master/src/com/thirtymatches/toasted/ToastExpander.java 에서 쓰레드로 시간을 빼면서 루프를 돌리는 방법도 있습니다.

저작자 표시
Tag // Android, Toast
올해가 벌써 한 달이 가까워지게 지나가고 있다.
세월은 엄청 빠르게 지나가고 있다.. 특히, 내가 나이가 먹으니 더 느껴진다.. ^^;;
작년에 대한 포스트 모텀이지만, 작년을 얘기하려면 제 작년에 N사를 그만두면서 느꼈던 시간의 아까움에 대해서 얘기를 해봐야겠다..

시간,, 정말 중요한 거 같다.. 경력이 주로 N사다 보니 참 편하게 회사에 다녔던 거 같다..
그리고 정말로 나오기 전에 롤 모델로 삼고 싶은 CTO님을 만나게 된 것이 행운이었다.. 어찌 보면 아이러니 하지만, 그분을 보면서 시간의 아까움과 뭔가를 해봐야겠다라는 생각을 강렬하게 받았기 때문이다..
그래서 결국 N사를 퇴사하고 비교적 고행(?)길로 들어서게 되었다.. ^^

그래서, 작년에 한 일에 대해서 얼추 얘기해 보자면..

1. 전 직장에서 퇴사하다..
잘한 결정이고 후회는 없다..
아키텍처링과 백엔드의 경험은 매우 좋았다.. 그리고, 당근 좋은 분들을 알게 된 게 가장 알찬 거겠지.

2. 카산드라 완벽 가이드를 번역하다.
 개인적으로 작년에 최대의 산출물이라고 생각한다. 그 이유는 번역을 하면서 오랜만에 집중해서 공부를 해본거 같다.. 선배 형하고 같이 진행을 하면서, 서로 바쁜 업무로 인해서 쉽지는 않았지만, 정말 편집자(한동훈님)를 잘 만나서 매우 만족을 한다.. 실제 업무에서 카산드라를 사용하고 있었고, 번역하면서 카산드라에 대한 경험치를 많이 터득할 수 있었다.

3. 안드로이드 앱을 런칭하다.
전 회사에서 아이폰 앱을 런칭하려고 시도했으나, 매우 힘들게 진행되는 것을 보고 답답했었다.
그래서, 지금 회사에 TO가 모바일 쪽이었고, 커리어에 대한 고민은 하긴 했지만, 우선 고하기로 했다.
그리고, 작년에 첫 타블릿 앱이 출시가 되었다. 처음 개발한 앱이라서 힘도 들긴 했지만, 그럭저럭 좋은 앱을 개발한 거 같아서 좋다.. 작년부터 지금까지 새로운 안드로이드 앱을 준비하고 있다.. 이 앱은 우여곡절이 좀 있다.. 일 하기가 매우 힘들었고, 난항도 많았다.. 그래도, 거의 개발이 완료가 되서 출시를 목전에 두고 있다..

이 내용은, 별 감정이 개입되지 않은 일련의 업무의 타임라인이라고 할 수 있겠다.

이제, 제 작년부터 준비를 했던, 실리콘 밸리에서의 개발자로서의 삶을 목전에 두고 있다.
어찌보면 영어도 못 하면서 실리콘 밸리에 있는 회사를 들어갔으니, 나름 성공적으로도 보일 수 있겠다. 
개인적으로, 미국에 있었던 반년은 매우 힘들었다. 정말 몰랐으니 덥썩 덤벼든 거였다.. 가족이 있다보니, 가족과 떨어져 있는 것이 이렇게 힘들다는 것을 뼈져리게 느끼게 되었다.
앞으로 누구한테도 가족과 떨어져서 일을 오래해야 하는 형태는 추천하지 않겠다..

그리고, 영어가 부족하다 보니, 일할때 문제가 생기곤 한다. 소프트웨어 개발은 다양한 컨텍스트 상황에서 어떻게 처리를 해야 하는지 명확하게 짚어야 하고, 결정된 내용을 잘 구현해야 좋은 소프트웨어를 개발할 수 있겠다.
그런데, 명확하게 이해를 하지 못하는게 간혹 있기도 하다.. 다행이 나는 옆에서 일하는 개발자가 영어를 잘해서 통역도 해준다.. 땡큐.. ^^
영어는 생존이 걸려 있기 때문에 열심히 해야될 필요가 있겠지만서도 개발과 영어 둘 다 집중할 시간에 대한 선택을 한다면 또 다시 개발을 잘하기 위한 시간에 투자를 할것 같다..

한국에서는 실리콘 밸리가 개발자들의 천국이라고 말하고 있다. 과연 모가 개발자들에게 어필할 수 있기에 천국이라는 표현을 과감하게 썼을까 하는 고민을 해 본다..
천국이라.. 너무 과분한 표현 아닌가? 과분을 떠나 단지 미국에서 일하는 것에 대한 환상 아닐까?
요즘의 국내에서의 개발자들에 대한 대우도 좋아지고, 인식도 매우 좋다. 기술력도 그렇게 나쁘지 않다고 생각한다.
다만, 국내의 유수의 기업에서는 소스에 대한 공개와 유지에 대한 비용문제에 대해서 좋지 않은 견해를 가지고 있는 회사들이 많고, 회사 내부에서도 기득권에 대한 유지를 위해서 소스공개를 터부시하는 문화도 한 목 하기 떄문일 것이라 생각한다..

실리콘 밸리에서 개발자로서의 삶을 살아가기 위해서, 다시금 맘 가짐을 잡자면, 잘 할수 있는것에 집중을 하자이다..
단지 수요에 비해서 공급이 못 따라가는 것이라는 느낌이라서, 경쟁력을 가지는게 현명할 대처일 수 있다는 마지막 소견이라는.. ^^
저작자 표시
Facebook은 정말 플랫폼 회사라고 할 수 있는 다양한 SDK를 지원하고 있고, 그 중에 안드로이드에서 Facebook을 쉽게 연동할 수 있는 SDK가 있습니다.. 보통 SDK라고 하면, 전통적인 관념에서 보자면, 소트프웨어를 개발하가 위해서 지원하는 툴킷을 포함한 라이브러리(?)라고 정의할 수 있겠습니다..

그런데, Facebook SDK를 받아서 사용해 보면, 라이브러리는 아니지만, 그렇다고 해서 SDK라고 봐야 하는지도 약간은 의문인데.. 형태는 프레임웍의 모습을 띄고 있습니다.. 흠, 모습이 좀 애매해서, 그냥 SDK라고 봐야 하나 봅니다..
서두가 너무 길었네요.. ^^;;

제가 안드로이드에서 Facebook을 연동하면서 이슈가 될 만한 것중에 2가지를 골라봤습니다..

1. 인증창이 안뜨는 경우가 종종 발생한다..
제가 2.2와 2.3버전에서 테스트를 해 봤는데, 에뮬레이터는 잘 동작합니다..
하지만, 폰에 설치를 해보니, 되는 폰도 있고 아닌 것도 있습니다..
그래서, 인증창을 띄울때 기존의 예제에서 조금 더 추가해줘야 할 필요가 있습니다.  

- 예제코드(http://developers.facebook.com/docs/mobile/android/build/)는 아래의 코드입니다.. 
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 값을 변경해야 합니다..

위의 기본적인 2가지만 해결하면 사용하는데 이슈가 별로 없을 것 같습니다.. ^^
저작자 표시
보통 Base64는 특수문자나 바이너리를 인코딩해서 네트웍이나 파일처리를 위해서 사용합니다.
물론, 설정파일에 입력하기 어려운 " 이나 특수문자가 포함된 데이터는 설정파일에 넣게 되면 에러가 발생하게 됩니다..

그래서, 민감한 데이터를 암호화해서 로컬에 저장하기도 하는데, 암호화를 하다보면 특수문자 때문에 데이터가 로컬의 설정파일에 들어가지 않는 경우가 종종 발생합니다.. 그 때도 Base64로 인코딩해서 저장을 하면 쉽게 해결이 됩니다..

그래서, 간단한 Base64 클래스를 끄적여 봅니다..

import java.io.UnsupportedEncodingException;
import android.util.Base64;

/**
 * <pre>
 * net.sjava.android.util.Base64Util.java
 * </pre>
 *
 * @author : mcsong@gmail.com
 * @version :
 * @data : 2011. 10. 2. 오후 3:34:23
 *
 */
public class Base64Util {
    
    /**
     * Encode txt
     * @param txt
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String encode(String txt) throws UnsupportedEncodingException {
        byte[] data = txt.getBytes("UTF-8");
        return Base64.encodeToString(data, Base64.DEFAULT);
    }
    
    /**
     * Decode txt
     * @param txt
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String decode(String txt) throws UnsupportedEncodingException {
            return new String(Base64.decode(txt, Base64.DEFAULT), "UTF-8");
    }
}


저작자 표시
Tag // Android, BASE64
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도 있구요..
흠... 아무리 해도 안되네요.. ^^;;

그래서, 이클립스를 다시 재시작을 했습니다.. 잘됩니다..
젠장, 그래서 결론은 문제가 없어 보이는데, 에러가 발생하면, 재시작.. 재시작이 중요한 해결책이 될 수 있겠네요.. ^^
저작자 표시
Tag // ADT, Android, XML
Dialog는 안드로이드에서 자주 사용되는 UI 컴퍼넌트이지요..
그런데, Dialog를 show()하고 종료하기 위해서, cancel(), dismiss()를 사용할 수 있는데요..
API 문서에서는 아래와 같이 설명을 하고 있습니다.. 제가 UI쪽은 거의 안해봐서 그런가? 동작하는게 똑 같아 보입니다..


void cancel()
Cancel the dialog.

void dismiss()
Dismiss this dialog, removing it from the screen.


흠.. 몬 차이가 있을까요??
소스에 자세한 설명이 있네요.. 젠장..^^;;

아래 canel() 메소드를 호출하면 mCancelMessage가 있으면 보내주고, dismiss()를 호출하는 구조이고, onCancelListener에서 선언한 메소드를 호출해 준다고..

Cancel the dialog. This is essentially the same as calling dismiss(), but it will also call yourandroid.content.DialogInterface.OnCancelListener (if registered).
 
     public void cancel() {
         if ( != null) {
             
             // Obtain a new message so this dialog can be re-used
             Message.obtain().sendToTarget();
         }
         dismiss();
     }


아래 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 in onStop().
 
     public void dismiss() {
         if (Thread.currentThread() != ) {
             .post();
         } else {
             .run();
         }
     }


흠.. API 문서를 봐서 잘 이해가 안되는 메소드는 역시, 소스를 살펴봐야 됩니다..
역시 소스에 답이 있다는 진리는 변하지가 않는 것 같습니다.. ^^


저작자 표시
 Google Analytics for Android는 http://code.google.com/mobile/analytics/docs/android/ 에서 다운로드를 받고.. libGoogleAnalytics.jar 파일을 프로젝트의 lib 폴더에 복사를 하고, build path에 잡아서 사용하면 된다..

대충 예제 코드만 보면, 버튼의 클릭은 trackEvent, Activity를 로딩해서 데이터를 가져오는 형태는 trackPageView 메소드를 호출해서 통계자료로 사용하는 것으로 보인다.. 그리고, 코드는 일정시간이 지나면 Cron 잡처럼 디스패칭해서 데이터를 서버(Google Analytics)로 전송하는 형태라는 것을 알려주고 있다.

흠,, 그래도 도대체 어떻게 구현했는지가 궁금했다.. 그래서, 살짝 까본 결과는 아래와 같다.

* GoogleAnalyticsTracker는 static 인스턴스로 전형적인 싱클톤 패턴의 형태를 띠고 있다.

* 예제의 startSession 메소드를 호출하게 되면
 ** 이벤트를 저장할 데이터베이스를 생성한다
 ** 네트웍으로 처리할 디스패처를 생성한다..
 ** 디스패처의 콜백을 받을넘을 생성한다..
 ** 네트웍 연결관리하는 매니저를 생성하고..
 ** 안드로이드의 Handler를 하나 생성한다.. 이넘의 용도는 Timer의 schedule메소드와 비슷하게 일정시간 뒤에 등록한 Handler의 메소드를 실행한다..

* 예제의 trackEvent를 호출하면..
 ** 이벤트 객체를 만들어서, 위의 Handler객체의 postDelayed메소드를 사용해서 디스패처를 구동한다.

* 예제의 stopSession을 호출하면..
 ** 디스패처를 종료한다.. 결국 서버에 리포팅하는 쓰레드를 종료한다는 것이다..

흠, 위 과정이 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");
  }

  public NetworkDispatcher(String paramString1, String paramString2)
  {
    this(paramString1, paramString2, "www.google-analytics.com", 80);
  }

  NetworkDispatcher(String paramString1, String paramString2, String paramString3, int paramInt)
  {
    this.googleAnalyticsHost = new HttpHost(paramString3, paramInt);
    Locale localLocale = Locale.getDefault();
    this.userAgent = String.format("%s/%s (Linux; U; Android %s; %s-%s; %s Build/%s)", new Object[] { paramString1, paramString2, Build.VERSION.RELEASE, localLocale.getLanguage() != null ? localLocale.getLanguage().toLowerCase() : "en", localLocale.getCountry() != null ? localLocale.getCountry().toLowerCase() : "", Build.MODEL, Build.ID });
  }
}

자, 결론이다..

Google Analytics for Android를 사용하기 전에, 혹시 앱에 성능이슈를 유발할까? 또는 네트웍이 안 되면 문제가 생기지 않을까? 하는 의문은 역시 코드가 답을 해 준다.. 한마디 더 덧붙이자면, 코드 잘짰넹.. ㅋㅋ
저작자 표시
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도 지원하고 있네요.. 

4. http://jsonformatter.curiousconcept.com/
 JSON Formatter와 Validator를 지원합니다.. 


위의 사이트중 한개만 즐겨찾기 해 놓으면, JSON 포맷 기반의 프로젝트 하기에 편할 것으로 생각이 듭니다..
저작자 표시
Android 기반의 앱을 개발하다 보면, 해상도 문제가 골치 아프다..
특히, 태블릿을 지원하기 시작하는 허니콤이나, 모바일과 태블릿을 같이 지원하는 아이스크림까지 나온 상황에서는 말이다..

물론, 해상도에 적합하게 xml을 선언해서 개발하라고 하는 구글의 가이드(Supporting Multiple Screens)도 있지만, 다양한 해상도를 지원하기 위해서 /res/blahblah/layout.xml을 만들라고 하는것은.. 해상도에 맞춰 앱의 퀄리티를 유지하는 방향으로는 좋겠지만, 그 만큼 개발비용(iOS에 비해)을 증가시킬게 분명하다.. 물론, 이렇게 해서 태블릿도 하나의 앱에서 지원하면 좋겠지만, 개발해 보니, 이렇게 분리해서 태블릿의 장점을 녹여낼 수 있을까?라는 질문에는 회의적이다..

그래서, 개인적으로 도달한 답은 모바일 앱과 태블릿 앱을 분리해서 개발하는 게 좋을 듯 하다..
그럼, 각각의 앱을 개발하면서 각자(모바일, 태블릿)의 해상도는 어떻게 지원할 것인가? 에 대한 대답은 layout_weight으로 UI를 구성하는 것이다..

아래의 예제에서 빨간색으로 구성한 것들이 <LinearLayout>에서 각 UI가 차지하는 %를 숫자로 표현한 것이고, weightSum은 없으면 알아서 배열을 하지만, 아래의 예에서는 입력을 해 놓았다..

그리고, horizontal이든지 vertical이든지 비율로 크기를 맞추기 위해서는, 가로를 맞추기 위해서는 layout_width, 세로로 맞추기 위해서는 layout_height을 '0dp'로 입력을 해 두면 된다..

흠, 자 이렇게 하면, 다양한 해상도를 쉽게 지원할 수 있답니다...

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/linearLayout"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:background="#568dfb"
        android:weightSum="10.0"
        android:layout_gravity="center_vertical"
        android:layout_height="40dp">
  
        <TextView android:id="@+id/textView"
            android:text=" "
            android:visibility="visible"
            android:paddingLeft="8dp"
            android:layout_width="0dp"
            android:layout_weight="6"
            android:textColor="@android:color/white"
            android:layout_height="40dp"
            android:textAppearance="?android:attr/textAppearanceMedium"/>
  
           <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/linear_container"
            android:orientation="horizontal"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_weight="4"
            android:background="#568dfb"
            android:gravity="right"
            android:layout_gravity="center_vertical">
           
            <ProgressBar
                android:layout_gravity="right|center_vertical"
                android:background="#568dfb"
                android:layout_width="30dp"
                android:layout_height="30dp" />
           
            <TextView
                android:id="@+id/loadingTextView"
                android:layout_width="wrap_content"
                android:layout_height="40dp"
                android:layout_gravity="right"
                android:background="#568dfb"
                android:gravity="center_vertical"
                android:paddingLeft="4dp"
                android:paddingRight="4dp"
                android:text="Loading..."
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="@android:color/white"/>
        </LinearLayout>
    </LinearLayout>

저작자 표시
Android에서 Facebook SDK를 사용해서 인증하는 내용입니다.. 
기본적으로 Facebook Developer 페이지에서 자세한 내용을 설명하고 있습니다.. 
아래는 그 내용을 간략하게 정리한 내용입니다.. 

1.  https://github.com/facebook/facebook-android-sdk 다운로드 및 풀기
 1.1. 압축을 푼 프로젝트에서 facebook 폴더의 프로젝트를 eclipse에서 import 한다.. 

 

 1.2 기존의 프로젝트에 reference 걸기.. 
  - Project > Properties > Android > Library > Add로 com_facebook_sdk를 추가해 준다. 

  


2. OpenSSL 설치
 2.1. 리눅스 설치 : http://www.ibrtses.com/linux/openssl.html
 2.2. 윈도우즈 설치 : http://www.slproweb.com/products/Win32OpenSSL.html 에서 환경에 맞게 설치를 한다. 혹, bin 디렉토리가 PATH에 안 잡혀 있어서 Facebook에 등록해야 하는 해시키 생성에 실패할 수 있으니 확인이 필요함.. 

3. 해시키 만들고 등록하기..
 3.1 해시키 만들기 : 아래의 명령을 통해서 해시키를 만든다..  
  > keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64
 3.2 만들어진 해시키를 Facebook에 등록한다.. 
      Facebook Developer 페이지의 Step 5의 이미지를 보면 쉽게 확인할 수 있다. 

4. 테스트 하기..
테스트 코드도 역시 Facebook Developer 페이지에서 확인하면 좋다.. ^^
 
저작자 표시
요즘 데이터의 풍요속에서 데이터를 처리하기 위해서 필요한 데이터 전송 포맷이 매우 다양하죠..
따라서, 데이터를 네트웍으로 전송하기 위한 포맷을 선택하는 것이 시스템 전체적인 성능이나 유연성을 좌우하기에 매우 중요한 팩트가 되었습니다..

그래서, 데이터 포맷별로 테스트한 자료와 성능에 대한 검색자료를 정리해 봅니다.. ^^

1. Java Serialize Benchmarking

- 이 테스트 자료는 자바환경에서 https://github.com/eishay/jvm-serializers 프로젝트에서 테스트한 자료입니다.
- 테스트 결과중에 속도에 대한 차트만 첨부했습니다. 예전의 테스트 자료에서는 kryo가 protobuf보다 더 빠른 결과가 나왔었는데, 2011-07-13일 버전의 테스트 자료에서는 역전을 했네요.. ^^ 그리고, 위의 테스트 결과 위키에서의 답글(2011-10-27)을 보면, 테스트 결과에서는 kyro가 상당히 의미있는 결과를 보여주고 있네요.. 그리고 테스트 결과를 바탕으로 json 포맷을 지원하는 라이브러리 선택도 의미가 있을 것 같습니다.
- 이 테스트 자료는 상당히 방대한 자료에 대한 테스트를 진행했기 때문에 정말 유익합니다.. 꼭 자세히 살펴볼 필요가 있습니다.. 하지만, 최근(?)에 사용을 늘려가고 있는 MessagePack과 YAML에 대한 자료가 없는건 아쉽네요..


- 테스트한 결과에 대한 스냅샷을 위해서 .mht 파일로 첨부했습니다..
 



2. MessagePack에 대해서 고려한 카산드라..

- 카산드라 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.

(Results)
      create  ser +same deser +shal +deep total size +dfl
protobuf    683 6016 2973  3338  3454 3759 9775 239 149
thrift      572 6287 5565  3479  3616 3770 10057 349 197
msgpack    291 4935 4750  3468  3545 3708 8748 236 150
avro     2698 6409 3623  7480  9301 10481 16890 221 133

(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.


3. Serializing data speed comparison: Marshal vs. JSON vs. Eval vs. YAML

- 이 테스트 자료는 루비로 테스트를 했다고 하네요..
 

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:

                 user      system     total       realarray marshal  0.210000   0.010000   0.220000 (  0.220701)array json     2.180000   0.050000   2.230000 (  2.288489)array eval     2.090000   0.060000   2.150000 (  2.240443)array yaml    26.650000   0.350000  27.000000 ( 27.810609)
hash marshal   2.000000   0.050000   2.050000 (  2.114950)hash json      3.700000   0.060000   3.760000 (  3.881716)hash eval      5.370000   0.140000   5.510000 (  6.117947)hash yaml     68.220000   0.870000  69.090000 ( 72.370784)

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:

                 user      system     total       realarray marshal  2.080000   0.110000   2.190000 (  2.242235)array json    21.860000   0.500000  22.360000 ( 23.052403)array eval    20.730000   0.570000  21.300000 ( 21.992454)
hash marshal  19.510000   0.500000  20.010000 ( 20.794111)hash json     39.770000   0.670000  40.440000 ( 41.689297)hash eval     51.410000   1.290000  52.700000 ( 54.155711)

시스템을 설계하면서 네트웍으로 데이터를 전송/수신하기 위한 포맷은 위의 자료로 대부분 살펴본 것 같습니다.
개발하는 시스템의 성격에 따라서 속도와 사이즈 어떤 것이 중요할지는 개발자의 판단이고..
이 자료가 매우 도움이 되었으면 좋겠습니다.. ^^

저작자 표시
안드로이드 2.3 부터인가? AsyncTask 기반의 쓰레드 프로그래밍을 해야 합니다.. 그러다가 자주는 아니지만 가끔 android.view.WindowLeaked 에러를 토하면서 앱이 죽을 때가 있는데, 이런 경우에는 별도 쓰레드(AsyncTask 같은)를 실행한 Activity가 onPuase나 onClose 상태가 되면서 finish되는 상태가 되고, 별도 쓰레드(UI 작업을 하는)가 아직 실행중인 상태에서 발생을 하게 됩니다.. 결국, 현재 Context를 AsyncTask에서 사용하고 있는데, Context가 사라저 버려서 발생을 합니다.. 

그래서, 간단한 해결책을 살펴보자..
Dialog류의 작업을 보통 AsyncTask로 많이 구동시키는데..

1. Dialog를 클래스 변수로 선언을 한다..
private ProgressDialog dialog;
private Dialog d; 
2. 별도 쓰레드에서 클래스 변수를 인스턴스화해서 사용하자..
dialog = ProgressDialogFactory.create(AAAActivity.this, false);
3. Activity의 onPause나 onClose같은 상황이 되서 Activity가 finish되는 상황에서 dialog를 종료해 주자..
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
dialog = null;
}
if(d != null && d.isShowing()) {
d.dismiss();
d = null;
}
finish(); 

위 방식으로 프로그래밍을 하면 android.view.WindowLeaked 문제는 쉽게 해결하겠다.. ^^
저작자 표시

Java Magazine 11/12 2011

from Etc 2011/11/16 04:36
2011년 11월과 12월 자바 매거진입니다..


저작자 표시

'Etc' 카테고리의 다른 글

Java Magazine 11/12 2011  (0) 2011/11/16
ansi color code and text format  (0) 2011/01/20
YAML 파싱 라이브러리 : http://code.google.com/p/snakeyaml/
YAML 포맷을 수정하기 편하게 해 주는 에디터(Eclipse Plugin) : http://code.google.com/p/yedit/
YAML 포맷을 체크할 수 있는 사이트 : http://instantyaml.appspot.com/

흠.. 더 필요한게 또 뭐가 있을까??
저작자 표시
Tag // YAML
카산드라는 0.7 버전부터인가?? YAML 포맷의 파일을 설정파일로 사용하기 시작을 했다..
기존에는 YAML 파일은 JSON 포맷과 다른 또 다른 포맷으로만 알고 있었는데, 위키의 YAML 포맷에 대한 정의를 살펴보면, 사람이 쉽게 읽을 수 있는 데이터 직렬화 양식이라고 한다.. 흠 그래.. 쪼매 쉽게 읽히긴 한다..
아래에서 0.6 버전에서 사용했던 XML 포맷과 현재(1.0.2)에서 사용하고 있는 YAML 포맷을 살펴보자.. 어떤 설정이 더 가독성이 있을까? 라는 질문에 나는 XML 포맷이라고 답하겠다..

단순히 포맷만 보면, XML이 YAML 포맷에 비해서 비 효율적이고 파싱에 대한 비용도 많이 들겠다.. 하지만, 카산드라에서 아래의 용도는 클러스터/머신의 상황에 맞게 카산드라가 잘 돌게 하기 위한 설정이다.. 설정이라고 하면, 포맷에 맞춰서 설정한 값의 가독성이 매우 중요한 포인트라고 생각한다.  그런 면에서 나는 꼭 설정에 XML을 사용할 필요는 없겠지만, 가급적이면 YAML보다 쉽고(비교적 쉽게 느껴지는 주관) 가독성이 좋은 XML을 사용해 줬으면 하지만, 지금은 YAML 포맷이니.. YAML 포맷을 숙지하고 사용해야 겠지만, 아쉬운 느낌이다.. 아.. XML 포맷이 좋아지다니... ㅋㅋㅋ

<Storage>
  <ClusterName>Test Cluster</ClusterName>
  <AutoBootstrap>false</AutoBootstrap>
  <Keyspaces>
    <Keyspace Name="Keyspace1">
      <ColumnFamily CompareWith="BytesType"
                    Name="Standard1"
                    RowsCached="10%"
                    KeysCachedFraction="0"/>
      <ColumnFamily CompareWith="UTF8Type" Name="Standard2"/>
      <ColumnFamily CompareWith="TimeUUIDType" Name="StandardByUUID1"/>
      <ColumnFamily ColumnType="Super"
                    CompareWith="UTF8Type"
                    CompareSubcolumnsWith="UTF8Type"
                    Name="Super1"
                    RowsCached="1000"
                    KeysCachedFraction="0"
                    Comment="A column family with supercolumns, whose column and subcolumn names are UTF8 strings"/>
      <ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
      <ReplicationFactor>1</ReplicationFactor>
      <EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>    
    </Keyspace>
  </Keyspaces>

  <Authenticator>org.apache.cassandra.auth.AllowAllAuthenticator</Authenticator>
  <Partitioner>org.apache.cassandra.dht.RandomPartitioner</Partitioner>
  <InitialToken></InitialToken>

  <CommitLogDirectory>/var/lib/cassandra/commitlog</CommitLogDirectory>
  <DataFileDirectories>
      <DataFileDirectory>/var/lib/cassandra/data</DataFileDirectory>
  </DataFileDirectories>
  <CalloutLocation>/var/lib/cassandra/callouts</CalloutLocation>
  <StagingFileDirectory>/var/lib/cassandra/staging</StagingFileDirectory>

  <Seeds>
      <Seed>127.0.0.1</Seed>
  </Seeds>

  <RpcTimeoutInMillis>5000</RpcTimeoutInMillis>
  <CommitLogRotationThresholdInMB>128</CommitLogRotationThresholdInMB>
  <ListenAddress>localhost</ListenAddress>
  <StoragePort>7000</StoragePort>
  <ThriftAddress>localhost</ThriftAddress>
  <ThriftPort>9160</ThriftPort>
  <ThriftFramedTransport>false</ThriftFramedTransport>


  <DiskAccessMode>auto</DiskAccessMode>
  <SlicedBufferSizeInKB>64</SlicedBufferSizeInKB>
  <FlushDataBufferSizeInMB>32</FlushDataBufferSizeInMB>
  <FlushIndexBufferSizeInMB>8</FlushIndexBufferSizeInMB>
  <ColumnIndexSizeInKB>64</ColumnIndexSizeInKB>
  <MemtableThroughputInMB>64</MemtableThroughputInMB>
  <BinaryMemtableThroughputInMB>256</BinaryMemtableThroughputInMB>
  <MemtableOperationsInMillions>0.3</MemtableOperationsInMillions>
  <MemtableFlushAfterMinutes>60</MemtableFlushAfterMinutes>
  <ConcurrentReads>8</ConcurrentReads>
  <ConcurrentWrites>32</ConcurrentWrites>
  <CommitLogSync>periodic</CommitLogSync>
  <CommitLogSyncPeriodInMS>10000</CommitLogSyncPeriodInMS>
  <GCGraceSeconds>864000</GCGraceSeconds>
</Storage>

cluster_name: 'Test Cluster'
initial_token:
hinted_handoff_enabled: true
max_hint_window_in_ms: 3600000 # one hour
hinted_handoff_throttle_delay_in_ms: 50
authenticator: org.apache.cassandra.auth.AllowAllAuthenticator
authority: org.apache.cassandra.auth.AllowAllAuthority
partitioner: org.apache.cassandra.dht.RandomPartitioner
data_file_directories:
    - /var/lib/cassandra/data
commitlog_directory: /var/lib/cassandra/commitlog
saved_caches_directory: /var/lib/cassandra/saved_caches
commitlog_sync: periodic
commitlog_sync_period_in_ms: 10000

seed_provider:
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
          - seeds: "127.0.0.1"

flush_largest_memtables_at: 0.75
reduce_cache_sizes_at: 0.85
reduce_cache_capacity_to: 0.6
concurrent_reads: 32
concurrent_writes: 32
memtable_flush_queue_size: 4
sliced_buffer_size_in_kb: 64
storage_port: 7000
ssl_storage_port: 7001
listen_address: localhost
rpc_address: localhost
rpc_port: 9160
rpc_keepalive: true

rpc_server_type: sync
thrift_framed_transport_size_in_mb: 15
thrift_max_message_length_in_mb: 16
incremental_backups: false
snapshot_before_compaction: false
column_index_size_in_kb: 64
in_memory_compaction_limit_in_mb: 64
multithreaded_compaction: false
compaction_throughput_mb_per_sec: 16
compaction_preheat_key_cache: true
rpc_timeout_in_ms: 10000
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
dynamic_snitch_update_interval_in_ms: 100
dynamic_snitch_reset_interval_in_ms: 600000
dynamic_snitch_badness_threshold: 0.1
request_scheduler: org.apache.cassandra.scheduler.NoScheduler
index_interval: 128

encryption_options:
    internode_encryption: none
    keystore: conf/.keystore
    keystore_password: cassandra
    truststore: conf/.truststore
    truststore_password: cassandra


저작자 표시

Android Oftener 프로젝트..

from Android 2011/11/11 01:01
Android Oftener 프로젝트..
이 프로젝트는 간단하게 내가 자주 전화를 걸고, 문자를 보내는 사람들을 화면에 많이 보낸 순으로 정렬해 주고, 전화와 문자를 바로 보낼 수 있게 해 주는 유틸리티성 앱 프로젝트이다..

이 프로젝트는 간단하게 개발할 수 있어서 3~4일에 걸쳐서 개발을 했고, 디자이너(ideamplifier_at_gmail.com)인 존님의 도움을 받아서 나름 디자인을 입혔다..

개인적으로, 번들 Favorite이 좀 불편해서 개발을 했고, 많이 사용하는 앱이 되었으면 좋겠다..
아래는 캡쳐를 한 화면이다..

마켓 링크 : https://market.android.com/details?id=net.sjava.oftener&feature=search_result#?t=W251bGwsMSwyLDEsIm5ldC5zamF2YS5vZnRlbmVyIl0.

 


저작자 표시
아래 내용은 http://www.datastax.com/faq#intro-3 에 있는 내용입니다..
설명이 간단 명료해서 쉽게 차이점을 캐치하실 수 있습니다.. ^^
How does Cassandra differ from Hadoop?

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.


저작자 표시
우분투 11.10에 JDK설치하는 방법으로, 아래 내용은 http://blog.sudobits.com/2011/09/14/how-to-install-jdk-on-ubuntu-11-10/ 에서 더 자세하게 보실 수 있습니다.

* OpenJDK 설치..
sudo apt-get install openjdk-7-jdk
* Sun JDK 설치..
sudo add-apt-repository ppa:ferramroberto/java sudo apt-get update sudo apt-get install sun-java6-jdk sun-java6-plugin
저작자 표시
Tag // Java SDK, JDK, ubuntu
모바일 애플리케이션들은 대체로 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);

        
// sets up parameters
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf-8");
HttpConnectionParams.setConnectionTimeout(params, cTimeout);
HttpConnectionParams.setSoTimeout(params, sTimeout);

params.setBooleanParameter("http.protocol.expect-continue", false);

// registers schemes for both http and https
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
final SSLSocketFactory sslSocketFactory = SSLCertificateSocketFactory.getHttpSocketFactory(sTimeout, sessionCache);
//sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
registry.register(new Scheme("https", sslSocketFactory, 443));
ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(manager, params);
}


위 내용은 http://hi-android.info/src/android/net/http/AndroidHttpClient.java.html와 http://na.isobar.com/2011/best-way-to-use-httpclient-in-android/에서 참고했습니다.. ^^
저작자 표시
올해 작업했던 책이 드디어 출간을 합니다..
개인적으로 리서치 업무를 진행하면서 카산드라를 접하게 되었고, 업무에 카산드라를 적용해 보면서 많은 도움을 얻은 책을 번역하게 되서 너무 좋았습니다.. 그리고, 제가 좋아하는 형하고 같이 작업해서 아주 좋았습니다. 특히, 편집을 담당해 주신 한빛미디어의 한동훈님께서 너무 잘 정리를 해주셨습니다.. 비록, 카산드라 버전이 1.0.0의 정식버전이 런칭을 했지만, 책의 상당 부분이 0.6~0.7버전이 아닌 0.8 버전을 대상으로 작업을 해서 1.0.0을 적용하려는 분들께도 상당히 도움이 될 것으로 생각합니다..

 
책은 http://www.yes24.com/24/goods/5847220 에서 구매하실 수 있습니다..

* 오/탈역
- 번역서 147 페이지
이 플래스는 I/O가 아니라...
--> 이 플래그는 I/O가 아니라...
거짓 양성에 대한 주석부분에서.. 스팸 메일의 위험성에 대한 기술을 하고 있는데, 책에서 거짓 양성이 거짓 음성보다 덜 위험하다고 기술하고 있는데,,, 거짓 음성이 거짓 양성보다 덜 위험합니다..

거짓 양성에 대한 부분은 http://charsyam.wordpress.com/ 님께서 지적해 주셨습니다..

저작자 표시
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;

        queue.add(activity);
        if(queue.size() > size) {
            try {
                queue.take().finish();
            } catch (Exception e) {
                LogUtil.e(CNAME, LogUtil.TAG, ExceptionUtil.getException(e));               
            }
        }
    }
   
    public static boolean isRootActivity(Activity activity) {
        if(activity == null)
            return false;
       
        try {
            if(activity == queue.peek())
                return true;
        } catch (Exception e) {
            LogUtil.e(CNAME, LogUtil.TAG, ExceptionUtil.getException(e));               
        }
       
        return false;
    }

    public static void clear() throws InterruptedException {
        while(queue.size() > 0) {
            queue.take().finish();
        }
    }
}

* 사용방법
- Activity 생성(onCreate 메소드에서)시에 createActivity()를 호출한다. 자연스럽게 size만큼 Activity Stack이 관리가 된다.
- 앱 종료 detect는 isRootActivity()로 확인을 하면 된다.. ture인 경우 각 Activity 클래스에서.. onBackPressed()를 Override해서 확인하면 된다.. 참고로, AbstractActivity 클래스를 만들어서 상속을 사용하면 코드가 깔끔해 지겠다..
- 앱을 종료하면서 clear()를 호출해서 Activity stack에 있는 Activity들을 다 날려주셔야 Activity 관리가 명확해 집니다.. ^^

* 안드로이드 activity의 동작형태는 android:launchMode="standard" 에서 잘 동작합니다.. ^^

저작자 표시

Linux find 명령 option

from Os 2011/08/22 14:11
아래 내용은 에서 http://blog.naver.com/atra1203/150014157959 에서 발췌를 하였습니다..
 

/ 는 최상위 디렉터리를 뜻함. 만약 찾고자 하는 디렉터리가 있다면 그걸로 대체

- 파일 이름에 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/

 

- 여러개의 파일에서 특정 문자열을 바꾸기
   find / -name "*.txt" -exec perl -pi -e 's/찾을문자열/바꿀문자열/g' {} ; 
저작자 표시

'Os' 카테고리의 다른 글

Linux find 명령 option  (0) 2011/08/22
Ubuntu에 LibreOffice 설치하기..  (0) 2011/07/26
file descriptor 확인하기..  (0) 2011/06/08
amazon ec2 ubuntu partition 조정  (0) 2011/04/12
check directory/dir/file size in linux  (0) 2011/03/09
Tag // Find, linux