본문 바로가기

프로그래밍

AndroidQuery - 여러가지 유용한 기능을 담은 안드로이드 라이브러리

안드로이드를 개발하다 보면 굉장히 긴 코드를 작성해야 할때가 많습니다. 특히 네트워크 관련 프로그래밍을 할때는 코드가 복잡해지고 뭔가 이것저것 할것이 많다보니 코드가 길어지는 경우가 많습니다. 이런점을 해결하기 위해 나온 라이브러리가 Android Query입니다.

Android Queryhttp://code.google.com/p/android-query/

Android Query에는 다음과 같은 기능들이 있습니다.

  • Less Code
  • AJAX Callback
  • Image Loading
  • XML Parsing
  • Chaining
  • Binding
  • Authentication
  • In-app Version Check
  • Alleviate Fragmentation
  • Multiple UI, One Piece of Code
  • Less Code(UI Manipulation)

    다양한 기능이 있습니다. UI Manipulation같은 경우 android query를 이용하면 코드가 엄청나게 줄어들 수 있습니다.

    Without Android-Query

    public void renderContent(Content content, View view) {
            
            
            ImageView tbView = (ImageView) view.findViewById(R.id.icon); 
            if(tbView != null){
                    
                    tbView.setImageBitmap(R.drawable.icon);
                    tbView.setVisibility(View.VISIBLE);
                    
                    tbView.setOnClickListener(new OnClickListener() {
                                    
                                    @Override
                                    public void onClick(View v) {
                                            someMethod(v);
                                    }
                            });
                    
            }
            
            TextView nameView = (TextView) view.findViewById(R.id.name);    
            if(nameView != null){
                    nameView.setText(content.getPname());
            }
            
            TextView timeView = (TextView) view.findViewById(R.id.time);  
            
            if(timeView != null){
                    long now = System.currentTimeMillis();
                    timeView.setText(FormatUtility.relativeTime(now, content.getCreate()));
                    timeView.setVisibility(View.VISIBLE);
            }
            
            TextView descView = (TextView) view.findViewById(R.id.desc);    
            
            if(descView != null){
                    descView.setText(content.getDesc());
                    descView.setVisibility(View.VISIBLE);
            }
    }

    With Android-Query

    public void renderContent(Content content, View view) {
            
            AQuery aq = new AQuery(view);
            
            aq.id(R.id.icon).image(R.drawable.icon).visible().clicked(this, "someMethod");  
            aq.id(R.id.name).text(content.getPname());
            aq.id(R.id.time).text(FormatUtility.relativeTime(System.currentTimeMillis(), content.getCreate())).visible();
            aq.id(R.id.desc).text(content.getDesc()).visible();             
            
            
    }
    

    코드가 굉장히 줄어드는 것을 확인할 수 있습니다. 코드가 줄어드는것은 환영할만한 일인데 Android query를 사용한 코드에는 조금 문제가 있을 수 있습니다. Android Query는 뷰의 타입을 지정해주지 않고 사용합니다. 또한 예외처리 코드를 줄이기 위해서 해당하는 메쏘드가 존재하지 않으면 에러를 내지않고 넘어가 버립니다. 예를 들어 ImageView가 있다고 해봅시다. 이 뷰의 id는 imageView1이라고 합시다. 그리고 Android Query를 사용하여 다음과 같은 코드를 썻다고 합시다.

    aq.id(R.id.imageView1).text("Something");

    위의 코드는 분명 문제가 있습니다. imageView에는 text 속성이 없기 때문이죠. 하지만 Android Query의 특성상 이 코드는 뭔가 문제가 있다고 로그를 남길 테지만 에러를 내뱉지는 않습니다. 이렇게 되버리면 나중에 코드에 문제가 생겼을때 어디서 문제가 생긴지 파악하지 굉장히 어려워지는 경우가 생기게 됩니다.

    결론적으로 UI Manipulation에 Android Query를 사용하는 것은 비추합니다. Android Query는 chain 기능까지 제공하기 때문에 코드가 굉장히 간결해지고 깔끔해 질 수는 있습니다. 만약 간결한 코드를 굉장히 사랑하는 분이라면 Android Query를 사용할순 있겠습니다만, 개인적으로는 좋지 않다고 생각합니다. 대신에 Roboguice나  Android annotation에서 제공하는 View Injection기능을 활용하는 것을 추천합니다. 사실 UI Manipulation은 그냥 원래 쓰던대로 쓰는것이 가장 안전하다고 생각하긴 합니다. 코드를 깔끔하게 쓸려고 했다간 이상한 오류가 나는 경우가 많이 생겨서 말이죠. 하지만 외부 라이브러리를 잘 활용할 수만 있다면 굉장히 좋은 코드를 만들어 낼 수 있어서 Roboguice나 Android annotation같은 것들은 비추하진 않고 사용을 권장해드리고 싶군요.

    Ajax Callback

    Ajax Callback 같은 경우도 굉장히 코드가 간결합니다. 다른 라이브러리로 대표적인 것이 http://loopj.com/android-async-http/가 있습니다. 이 라이브러리와 비교해 봤을때 가장큰 특징은 아무래도 간결함입니다. 정말 Android Query는 극도의 간결함을 추구하는 라이브러리입니다. 다른 라이브러리는 보통 콜백클래스를 따로 만들어서 사용합니다. 아무래도 그게 자바스럽고 안전한 프로그래밍이지요. 하지만 Android Query는 메쏘드 명을 String으로 써서 사용합니다. 그래서 따로 클래스를 만들지 않아도 됩니다. 하지만 아무래도 String으로 메쏘드 명을 쓰게 되면 나중에 메쏘드 명을 바꾸거나 하게 되면 알 수 없는 오류가 발생할 확률이 늘어나게 됩니다. 결국 Ajax Callback도 간결한 코드를 굉장히 좋아하시면 사용하셔도 됩니다. 

    Image Loading

    Image Loading 기능을 가진 다른 라이브러리도 많이 있습니다. 다른 라이브러리와 비교했을때 Android Query의 특징은 간결함입니다. 결국 간결함 이네요. 다음은 웹에서 이미지를 갖어오는 코드입니다.

    aq.id(R.id.image1).image("http://www.vikispot.com/z/images/vikispot/android-w.png");

    앱 내부 res폴더에서 이미지를 갖어오는 코드에서 R.drawable.xxx 부분이 URL로 바뀌었을 뿐입니다. 이것은 분명 큰 장점이 있습니다. 내부 이미지나 웹 이미지를 동일하게 다루게 됨으로서 코드의 통일성을 유지시킬 수 있습니다. 하지만 반대로 내부 이미지와 웹 이미지의 구분이 어려워서 문제가 생길 수도 있겠죠. 어쨋든 통일성을 유지한다는 점에서는 굉장히 만족스럽고, 코드도 다른 라이브러리를 사용하는것에 비해 굉장히 짧습니다. 게다가 메쏘드 chain기능을 지원하기 때문에 이미지를 설정하기도 수월합니다. 이런 좋은 장점이 있지만 한가지 마음에 걸리는 부분은 Android Query의 UI Manipulation 코드를 사용해야 한다는 부분입니다. 사실 통일성을 유지한다고 하면 모든 코드에서 UI Manipulation은 Android Query로 처리를 해야하겠죠. 그래서 조금 마음에 걸리긴 하지만 컨셉은 괜찮다고 생각됩니다.

    Chaining

    이 부분은 지금까지 여러번 언급했으므로 넘어가도록 하겠습니다. 분명한점은 Chaining은 Android Query가 강력할 수 있는 중요한 요소입니다.

    Binding

    Android Query를 사용하면 Listener를 사용하기 편리해 집니다. 따로 Listener 클래스를 만들지 않아도 되고 내부 클래스로 만들지 않아도 되고 Listener 인터페이스를 implement 하지 않아도 됩니다. 하지만 문제점은 Binding을 할때 메쏘드명으로 Binding을 한다는 것이지요. Ajax Callback 부분과 마찬가지로 말입니다. 이 부분은 Ajax Callback에서 열심히 떠들었으므로 넘어가도록 하곘습니다. 결국 판단은 여러분께.

    Authentication

    인증부분입니다. 구글, 페이스북, 트위터의 로그인 기능을 지원합니다. 굉장히 편하게 로그인 할 수 있습니다. 예제 코드는 다음과 같습니다.

    aq.id(R.id.image1).image("http://www.vikispot.com/z/images/vikispot/android-w.png");
    
    [코드 5]
    GoogleHandle handle = new GoogleHandle(this, AQuery.AUTH_PICASA, AQuery.ACTIVE_ACCOUNT);
    
    String url = "https://picasaweb.google.com/data/feed/api/user/default?alt=json";
    aq.auth(handle).ajax(url, JSONObject.class, new AjaxCallback(){
            @Override
            public void callback(String url, JSONObject object, AjaxStatus status) {
                    System.out.println(object);
            }
    });     

    굉장히 간단하지요? 보통은 이것 저것 해야되서 귀찮은데 말이죠. 사용하시면 편하게 로그인 기능을 구현할 수 있습니다.

    Alleviate Fragmentation

    Alleviate Fragmentation은 한글로 파편화 완화입니다. 언뜻 들으면 꿈만 같은 기능입니다. 안드로이드의 파편화가 개발자를 힘들게 만드는 엄청 큰 요소라는것은 누구나 동의할 겁니다. 근데 Android Query의 Alleviate Fragmentation은 꿈만 같은 기능은 아니고 오히려 잘못되면 개발자를 파멸로 이끌 수도 있습니다. UI Manipulation부분에서 한번 설명했듯이 Android Query는 뭔가 메쏘드가 없으면 오류를 내뱉지 않고 로그를 남기고 그냥 넘어가 버립니다. API도 마찬가지입니다. Android Query를 이용해 작성한 코드에서 API Level 8인 프로요에서 API Level 13인 허니콤의 기능을 사용했다고 하면 앱은 오류를 내뱉지 않고 그냥 넘어가 버립니다. 이것이 Alleviate Fragmentation기능입니다. 특정 플랫폼에서 오류가 나는 것을 방지할 순 있지만 이유를 알 수 없는 버그가 발생할 수 있습니다. 눈에 보이는 오류보다 이유를 알 수 없는 버그를 수정해야하는 것이 훨씬 어렵고 곤욕스러운 일이지요. 어쨋든 API 레벨에 따른 조금씩 다른 기능을 제공하고자 할 때는 Android Query를 사용하는 것이 유용할 수 있겠으나, 어떤 기능이 반드시 작동해야 하고 어떤 기능이 작동해도 되고 안해도 되고 같은 것들이 확정되지 않았다면 지양해야 합니다.

    Mutiple UI, One Piece of Code

    한번의 코드로 여러개의 UI(타블렛 UI, 폰 UI)를 지원할 수 있는 기능입니다. 정확히 말하면 동일한 코드로 다양한 플랫폼을 지원한다는 것은 아니고 한곳에 폰 UI용 코드와 타블렛 UI용 코드를 같이 써 놓으면 폰 UI 코드는 타블렛에서 무시되어 버리고 타블렛 UI는 폰에서 무시되어 버리는 겁니다. 지금까지 말했듯이 뭔가가 없으면 그냥 넘어가는 겁니다. 이 방법의 단점은 지금까지 설명했으니 넘어가도록 하겠습니다.


    지금 살펴본 Android Query의 큰 특징은 3가지 라고 할 수 있겠네요. 하나는 없으면 넘어간다. 두번째는 chaining. 세번째는 string 메쏘드 바인딩. 

    Chaining 기능은 딱히 단점이 없다고 생각됩니다. 문제는 첫번째와 세번째 입니다. 특정 메쏘드가 없으면 그냥 넘어가버리는 기능을 사용하면 분명 코드가 불안정해지긴 하지만 그로 인해 얻을 수 있는것이 많아서 조금 갈등되는 부분입니다. string 메쏘드 바인딩도 유지 보수가 어려운 코드를 만들어 버리긴 하지만 확실히 코드를 단순화 시킬 순 있죠. 그런데 string 메쏘드 바인딩은 되도록 쓰지 않는게 정신건강에 좋은것 같습니다.



    추가: 알고보니 Android Query에서 Event Binding이나 Callback을 string 메쏘드로 바인딩 하지 않고 클래스로도 할 수 있네요. 클래스로 쓰시고 싶으신 분은 클래스로 써도 되겠습니다. 그렇게 하는 것을 더욱 추천드리기도 하고요.