실패 이야기 - MVVM Pattern in Android

안드로이드를 하면서 새로운 도전중 관심이 생긴 MVVM과 같은 패턴에도 신경을 쓰기 시작했다. 마침 좋은 안드로이드 지원 라이브러리, Plugin이 있어서 적용하였지만 생각보다 별로인 부분이 상당히 있었다.

처음 시작할 때는 AndroidAnnotation을 이용하였고 View Inject에 많은 도움을 받았지만 ANT부분에 상당한 자원이 소모되는지 빌드시간이 너무 길고, 중간중간 빌드를 통해 Activity_.class와 같이 _클래스를 생성해줘야해서 불편했다.`

그다음 선택한 방식은 디자인 패턴을 알아보다가 알게된 Android Data Binding이다. Gradle Plugin을 이용한 백그라운드로 알아서 Bind가능한 클레스를 만들어주고, 최근(??)기술이라 빌드속도에도 문제가 적었다. 또한 View Binding으로 XML에서 로직을 다룰 수 있다는 점에서 맘에 들었다. 하지만 Pure한 뷰가 아니라 유지보수가 힘들고????? 먼가 깔끔하지 않았다.

Binding Adapter를 남용하는 느낌이 들었을때 그냥 맘에 안들게 되었고, 본격적으로 Kotlin을 시작하게되면서 사용하지 않게되었다. Kotlin에 Data Binding라이브러리가 충돌?나면서 안쓰게 되었습니다.

Binding Adapter이지만 남용한 느낌이 물씬드는 코드들이다.

1. TextView

Html Text Setting

@BindingAdapter({"app:html"})
public static void setTextHtml(TextView textHtml, String html) {
    Spannable spannable = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        spannable = (Spannable) Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
    } else {
        spannable = (Spannable) Html.fromHtml(html);
    }
    textHtml.setText(spannable, TextView.BufferType.SPANNABLE);
}
// viewDataBinding.setTextHtml(“<u>underline</u>”);

2. RecyclerView

Set adapter

@BindingAdapter({"app:adapter"})
public static void setAdapter(RecyclerView recyclerView, RecyclerView.Adapter adapter) {
    recyclerView.setAdapter(adapter);
}

Set Layout Manager

@BindingAdapter({"app:layoutManager"})
public static void setLayoutManager(RecyclerView recyclerView, int spanCount) {
    switch (spanCount) {
        case 0 :
            recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
            break;
        default:
            recyclerView.setLayoutManager(new GridLayoutManager(recyclerView.getContext(), spanCount));
    }
}

3. EditText

Two way binding

@BindingAdapter(value = {"app:text"})
  public static void setText(EditText editText, ObservableString observableString) {
      editText.addTextChangedListener(new TextWatcher() {
          @Override
          public void beforeTextChanged(CharSequence s, int start, int count, int after) {

          }

          @Override
          public void onTextChanged(CharSequence s, int start, int before, int count) {
              observableString.set(s.toString());

          }

          @Override
          public void afterTextChanged(Editable s) {

          }
      });

      String newValue = observableString.get();
      if (!editText.getText().toString().equals(newValue)) {
          editText.setText(newValue);
      }
  }

4. ViewPager

Set adapter

@BindingAdapter({"app:adapter"})
public static void setAdapter(ViewPager viewPager, PagerAdapter adapter) {
    viewPager.setAdapter(adapter);
}

Set onPageChangeListener

@BindingAdapter({"app:onPageChange"})
public static void addOnPageChangeListener(ViewPager viewPager, ViewPager.OnPageChangeListener listener) {
    viewPager.addOnPageChangeListener(listener);
}