AW201: 아답터 재사용, Realm과 Parceler로 Retrofit 쓰기, PNG 파일 사이즈 줄이기

Android Weekly는 매주 발행되는 안드로이드 뉴스레터입니다. 영어 기사를 정독할 시간이 없는 분을 위해 핵심 꼭지를 요약했습니다.

주간 안드로이드 뉴스를 요약해 드립니다. Android Weekly 201 원문도 읽어보세요.


코드 생산성을 높이는 안드로이드 스튜디오 사용 팁

aw201-android studio tips intro

  1. 범위를 지정한 후 자동완성이 나오면 탭으로 현존하는 메서드와 밸류를 교체할 수 있습니다.
  2. ALT를 조합한 단축키를 활용해 보세요. ALTUP 혹은 ALTDOWN 버튼을 함께 누르면 선택 범위를 늘리거나 줄일 수 있습니다.
  3. postfix를 활용하면 loop, if, log 등 자주 사용하는 코드를 쉽게 완성할 수 있습니다.
  4. 객체에 custom renderer를 사용해서 디버깅을 간편하게 할 수 있습니다. 자세한 설명은 원문을 참조하세요!
  1. IntelliJ IDEA 13.1이 기본적으로 제공하는 멀티플 커서를 활용하면 특정 단어를 쉽게 선택할 수 있습니다. Ctrl-G (Win/Linux: Alt-J)를 누르면 다음 단어가 함께 선택됩니다. 이렇게 바꿀 단어를 모두 선택한 후 바꿀 단어를 그냥 타이핑하면 됩니다! aw201-android studio case01

  2. Cmd-Shift-U (Win/Linux: Ctrl-Shift-U)를 누르면 마법처럼 대소문자가 전환됩니다.
  3. Cmd-Shift-F / Cmd-Shift-R (Win/Linux: Ctrl-Shift-F / Ctrl-Shift-R) 단축키를 활용해서 파일뿐만 아니라 폴더 단위로도 탐색과 단어 교체가 가능합니다. 이 때 정규 표현식을 사용하면 다양한 옵션을 적용할 수 있는데 \l과 \u로 다음 문자를 소문자나 대문자로 바꿀 수 있습니다.

이런 개발 뉴스를 더 만나보세요

aw201-android studio case02

간편하게 다른 view 타입에 재사용할 수 있는 RecyclerView Adapter 만들기

  • view의 종류가 늘어날 수록 Adapter를 재사용하는 것이 점점 어려워짐을 느끼셨나요? 괴로움 없이 적용할 수 있는 Adapter 개발(Great Adapter Hell Escape)에서 MyLittleZoo라는 회사에서 일하는 개발자, Joe Somebody의 가상 사례를 통해 재사용 가능한 RecyclerView Adapter를 간편하게 만드는 과정을 살펴 볼 수 있습니다.

  • 앱에서 광고를 사용하는 view가 점점 늘어남에 따라 Joe는 AdvertisementAdapter를 extend해서 3개의 Adapter를 만들었습니다. 그런데 광고를 제거한 앱을 새로 출시하면서 AdvertisementAdapter를 더이상 사용할 수 없게 됐습니다. 이제 HomeAdapter를 새로 만들어서 extends해야 할까요?

“상속 보다 조합을 사용하는 편이 좋습니다.”

  • Joe는 이 원칙을 떠올리고 NewsTeaserAdapterDelegatePetFoodTipAdapterDelegate를 만들었습니다. AdvertisementAdapter 상속을 버리고 각 뷰에 델리게이트를 정의한 거죠. 각 델리게이트가 뷰홀더의 생성과 바인딩을 책임집니다. 다음처럼 멋진 플러그인을 만들 수도 있죠.
/**
 * @param <T> the type of adapters data source i.e. List<Accessory>
 */
public interface AdapterDelegate<T> {

  /**
   * Called to determine whether this AdapterDelegate is the responsible for the given data
   * element.
   *
   * @param items The data source of the Adapter
   * @param position The position in the datasource
   * @return true, if this item is responsible,  otherwise false
   */
  public boolean isForViewType(@NonNull T items, int position);

  /**
   * Creates the  {@link RecyclerView.ViewHolder} for the given data source item
   *
   * @param parent The ViewGroup parent of the given datasource
   * @return The new instantiated {@link RecyclerView.ViewHolder}
   */
  @NonNull public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);

  /**
   * Called to bind the {@link RecyclerView.ViewHolder} to the item of the datas source set
   *
   * @param items The data source
   * @param position The position in the datasource
   * @param holder The {@link RecyclerView.ViewHolder} to bind
   */
  public void onBindViewHolder(@NonNull T items, int position, @NonNull RecyclerView.ViewHolder holder);
}
  • 즉, AdapterDelegatesAdapterDelegatesManager에 등록한다는 아이디어죠. 더 상세한 설명과 전체 예제는 원문을 확인하세요.

Realm과 Parceler를 이용한 Retrofit 적용법

  • RESTful HTTP 통신을 위한 라이브러리, Retrofit을 사용하면 쉽고 빠르게 백엔드와 데이터를 주고 받을 수 있습니다. 게다가 SQLite 대신 Realm을 사용하면 객체 그대로 데이터를 사용할 수 있으므로 편리합니다. 한편 fetch된 객체를 데이터베이스에 저장할 때 onSaveInstanceState() 사용으로 액티비티가 죽는 상황을 방지하고 싶을 때는 Parceler를 유용하게 사용할 수 있습니다. 이 세 가지 라이브러리를 함께 사용하면 데이터를 백엔드에서부터 편하고 쉽게 가져올 수 있습니다. Realm과 Parceler를 이용한 Retrofit 적용법(Using Retrofit with Realm and Parceler)에서 차근차근 살펴볼까요? aw201-retrofit title
Retrofit
  • build.gradle에 관련 디펜던시를 추가합니다.
  • 모델 클래스를 정의하고 HTTP 요청을 위한 메서드와 URL을 annotation 형식으로 정의합니다.
public interface ICountryApi {
  @GET("region/{region}")
  Call<List<Country>> getAllCountries(@Path("region") String region);
}
  • Retrofit으로 해당 인터페이스를 implements해서 객체를 만듭니다. 이 객체는 의존성 주입이나 싱글턴을 사용해서 재사용할 수 있습니다.
  • 이제 Call.execute()로 service 객체를 사용해서 백엔드 요청을 할 수 있습니다. Response<ModelClass>가 반환됩니다. 비동기식으로 요청하려면 callback 기반인 Call.enqueue()를 사용합니다.
  • onResponse()에서 응답을 받고 body 등에 접근할 수 있습니다. 정말 쉽죠?
  • RxJava의 Observable<ModelClass> 반환 타입을 설정해서 백엔드 요청을 할 수도 있습니다.
Realm
  • build.gradle에 Realm 디펜던시를 추가합니다. 만약 용량이 부담된다면 APK 분리를 고려해 보세요.
  • Realm을 열고 쿼리를 보내기 위해 RealmObjects를 사용합니다. 스레드 기반이므로 다른 스레드에서 열기 위해서는 새로운 RealmObjects 객체를 사용해야 합니다. RealmObjects를 extends해서 모델 클래스를 정의하세요.
  • RealmList는 RealmObjects만을 담을 수 있으므로 primitive 타입과 스트링을 래핑해야 합니다. 스트링을 래핑한 RealmString 클래스처럼요.
  • Gson이 RealmString을 모르므로 TypeAdapter를 사용합니다.
  • GsonBuilder로 빌드할 때 TypeAdapter를 등록합니다.
  • 트랜잭션 단위로 접근할 수 있으므로 쓰기는 트랜잭션 안에서 이뤄집니다.
Parceler
  • 데이터 전달과 상태 저장을 위해서는 객체가 Serializable이나 Parcelable을 implement해야 하죠. 이에 따르는 오버헤드를 줄이는 것이 Parceler입니다.
  • 먼저 APT 플러그인을 적용한 뒤 Parceler 디펜던시를 추가합니다.
  • @Parcel로 클래스의 annotation을 넣을 수 있습니다. Realm과 함께 사용하기 위해서는 아래처럼 추가 설정이 필요합니다.
@Parcel(implementations = { CountryRealmProxy.class },
        value = Parcel.Serialization.FIELD,
        analyze = { Country.class })
public class Country extends RealmObject {
  @PrimaryKey
  public String alpha2Code;
  public String name;
  public String region;
  @ParcelPropertyConverter(RealmListParcelConverter.class)
  public RealmList<RealmString> languages;
  ...
}
  • analyzeimplementations 속성을 설정해서 Realm이 사용하는 프록시 클래스인 CountryRealmProxy 객체를 받도록 할 수 있습니다.
  • 기본 설정에서는 Parceler가 RealmList를 다룰 수 없으므로 ParcelConverter를 사용합니다.
  • @Parcel 어노테이션 객체를 Parcelable로 사용하려면 Parcels.wrap(object)으로 래핑합니다. 반대의 경우에는 Parcels.unwrap(parcelable)를 사용하는데 둘 모두 해당 객체의 List에도 사용할 수 있습니다. 정말 쉽죠?

PNG 파일 사이즈 줄이기

  • OOM과 ANR의 주범이 이미지 파일임은 익히 알고 계시죠? 개발자의 고민을 줄여줄 PNG 파일 사이즈 줄이기(Reducing PNG file Size) 기사를 소개합니다. PNG가 유연한 이미지 파일 포맷으로 인기 높지만 용량 뻥튀기가 쉽기 때문에 아무 생각없이 사용하다가는 자원 낭비가 심할 수 있다는 점에서 읽어볼 가치가 있어 보입니다!
  1. 최적화 도구를 사용하는 것이 좋습니다. PNGQuant, ImageMagick , PNGGauntlet, PNGOut 등 굉장히 많은 도구들이 있지만 필자는 zopfliPNG를 추천하고 있습니다.
  2. 비슷한 색을 줄여서 용량을 절약할 수 있습니다.
  3. 올바른 픽셀 포맷을 사용하는 것도 중요합니다. 예를 들어 알파가 없는 이미지라면 RGBA 32bpp 옵션은 전체 이미지의 ¼을 낭비하므로 24bpp truecolor 포맷을 사용하거나 그냥 JPG를 쓰는 것이 좋습니다.
  4. 인덱스 이미지를 사용하면 용량 절감에 도움이 됩니다.
  5. aw201-reducing-png01
  6. 투명 이미지를 최적화하는 것도 중요합니다. 보이지 않을 픽셀이 뭔지 알고 있다면 그 영역 모두가 동일하게 처리되도록 해야 압축에 도움이 됩니다. 특히 구멍이 뚫린 이미지인 경우 주의하세요.
  7. 인덱스 모드는 유용하지만 모든 이미지가 256가지 색 조합에 맞진 않죠. vector quantization을 통해서 수동으로 이미지 색상을 줄일 수 있습니다. pngquant 도구를 활용해 보세요.

더 읽을 거리

4월 셋째 주의 기사를 Android Weekly 201 영어 원문에서 볼 수 있습니다.

지난 뉴스가 궁금하다면 아래 링크를 참고해 주세요.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Realm Korea

Realm Korea Team

4 design patterns for a RESTless mobile integration »

close