실패 이야기 – 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(“underline”);

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

Node self number example

What is self-number

설명

A self number, Colombian number or Devlali number is an integer that cannot be written as the sum of any other integer n and the individual digits of n. This property is specific to the base used to represent the integers. 20 is a self number (in base 10), because no such combination can be found (all n < 15 give a result < 20; all other n give a result > 20). 21 is not, because it can be written as 15 + 1 + 5 using n = 15. Self Number

Kor 어떤 자연수 n이있을때 d(n)을 n의 각 자릿수 숫자들과 n자신을 더한 숫자라고 정의하다. 예를 들어 d(91)=9+1+91=101 이때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네러이터이다. 어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91뿐 아니라 100도 있다. 그런데 반대로, 제네레이터가 없는 숫자를 셀프넘버(self number)라고 한다.

코드

초기화

const MAX_VALUE = 5001; // Rage Array는 (0 ~ MAX_VALUE) - 1 이다 

var numberSet = new Set(Array.from(Array(MAX_VALUE).keys())); // 자바스크립트 : Rage Array만들기.

로직

var _func = function (number) {
  if (number > 0 && number < MAX_VALUE) {
    var _number = (""+number).split("").map(Number).reduce(function (x, y) { return x + y}) + number // generator 구함
    numberSet.delete(_number);
    _func(_number); // array에서 delete할 경우 forEach에 검사되지 않아서 재귀해준다.
  }
};
    
numberSet.forEach(_func); // 돌려주면 끝 - 

Q. 5000까지 Self Number에 합을 구하시요.

A. 1227365

p.s 넥슨 입사문제였다고 한다. javascript 기본 함수들을 몰라서 시간이 조금 소요되었다.

const MAX_VALUE = 5001; // self number max value - 1

var numberSet = new Set(Array.from(Array(MAX_VALUE).keys()));
var result = 0;
// delete self Number in set
var _func = function (number) {
  if (number > 0 && number < MAX_VALUE) {
      var _number = (""+number).split("").map(Number).reduce(function (x, y) { return x + y}) + number
      numberSet.delete(_number);
      _func(_number);
  }
};

numberSet.forEach(_func);
// Self Number sum
numberSet.forEach(function (number) {
  result += number;
});

// Result print
console.log(result);