MainActivity
public class MainActivity extends BaseActivity {
@NonNull
@Override
protected ViewModel createViewModel() {
return new MainViewModel(getNavigator());
}
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
}
BaseActivity
public abstract class BaseActivity extends MvvmActivity {
@NonNull
protected Navigator getNavigator() {
return new Navigator() {
@Override
public void openDetailsPage(Item item) {
navigate(ItemDetailsActivity.class);
}
@Override
public void navigateToFunctionalDemo() {
navigate(DataLoadingActivity.class);
}
@Override
public void navigateToAdapterDemo() {
navigate(ItemListActivity.class);
}
@Override
public void navigateToTwoWayBindingDemo() {
navigate(SearchActivity.class);
}
@Override
public void navigateToCalculatorDemo() {
navigate(CalculatorActivity.class);
}
private void navigate(Class<?> destination) { // 화면 이동
Intent intent = new Intent(BaseActivity.this, destination);
startActivity(intent);
}
};
}
@NonNull
protected MessageHelper getMessageHelper() {
return new MessageHelper() {
@Override
public void show(String message) {
Toast.makeText(BaseActivity.this, message, Toast.LENGTH_SHORT).show();
}
};
}
}
MessageHelper 인터페이스
public interface MessageHelper {
void show(String message);
}
MvvmActivity
public abstract class MvvmActivity extends AppCompatActivity {
private ViewDataBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, getLayoutId());
getDefaultBinder().bind(binding, createViewModel());
}
@Override
protected void onDestroy() {
getDefaultBinder().bind(binding, null);
binding.executePendingBindings();
super.onDestroy();
}
@NonNull
private ViewModelBinder getDefaultBinder() {
ViewModelBinder defaultBinder = BindingUtils.getDefaultBinder();
Preconditions.checkNotNull(defaultBinder, "Default Binder");
return defaultBinder;
}
@NonNull
protected abstract ViewModel createViewModel();
@LayoutRes
protected abstract int getLayoutId();
}
ViewModelBinder 인터페이스
public interface ViewModelBinder {
void bind(ViewDataBinding viewDataBinding, ViewModel viewModel);
}
Preconditions 클래스
public class Preconditions {
public static <T> void checkNotNull(T value, String name) {
if (value == null) {
throw new NullPointerException(name + " should not be null");
}
}
}
ExampleApplication ( 기본 애플리케이션 )
public class ExampleApplication extends Application {
public static RefWatcher getRefWatcher(Context context) {
ExampleApplication application = (ExampleApplication) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
BindingUtils.setDefaultBinder(BindingAdapters.defaultBinder);
}
}
CalculatorActivity 로 이동했어
public class CalculatorActivity extends MvvmActivity {
@NonNull
@Override
protected ViewModel createViewModel() {
return new CalculatorViewModel();
}
@Override
protected int getLayoutId() {
return R.layout.activity_calculator;
}
}
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="vm"
type="com.manaschaudhari.android_mvvm.sample.calculator_example.CalculatorViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
tools:context="com.manaschaudhari.android_mvvm.sample.calculator_example.CalculatorActivity">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Number 1"
android:inputType="number"
android:text="@={vm.number1}" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Number 2"
android:inputType="number"
android:text="@={vm.number2}" />
<RadioGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkedButton="@={vm.operation}">
<RadioButton
android:id="@+id/radio_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+" />
<RadioButton
android:id="@+id/radio_subtract"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="-" />
<RadioButton
android:id="@+id/radio_multiply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*" />
<RadioButton
android:id="@+id/radio_divide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/" />
</RadioGroup>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{vm.result}" />
</LinearLayout>
</layout>
CalculatorViewModel 에서 처리
public class CalculatorViewModel implements ViewModel {
public final ObservableField<String> number1 = new ObservableField<>("");
public final ObservableField<String> number2 = new ObservableField<>("");
public final ObservableField<Calculator.Operation> operation = new ObservableField<>(Calculator.Operation.ADD);
public final ReadOnlyField<String> result;
public CalculatorViewModel() {
final Calculator calculator = new Calculator();
Observable<String> result = Observable.combineLatest(
toObservable(number1), toObservable(number2), toObservable(operation),
new Function3<String, String, Calculator.Operation, String>() {
@Override
public String apply(String s1, String s2, Calculator.Operation operation) throws Exception {
try {
int n1 = Integer.parseInt(s1);
int n2 = Integer.parseInt(s2);
Integer result = calculator.run(n1, n2, operation);
return (result != null) ? result.toString() : "ERROR";
} catch (NumberFormatException e) {
return "";
}
}
});
this.result = toField(result);
}
}
Calculator 클래스
public class Calculator {
@Nullable
public Integer run(int a, int b, @NonNull Operation operation) {
switch (operation) {
case ADD:
return a + b;
case SUBTRACT:
return a - b;
case MULTIPLY:
return a * b;
case DIVIDE:
if (b != 0) {
return a / b;
} else {
return null;
}
}
return null;
}
public enum Operation {
ADD, SUBTRACT, MULTIPLY, DIVIDE
}
}
이렇게 하는 이유...
Rxjava : 일단 옵저버 패턴, 관측하고 있다가 변경사항이 있을 때 자동으로 메소드가 호출되는 방식(이 경우에는 run)
Mvvm : 클래스간의 종속성을 최소화 하고 (자바의 특징인 객체생성 및 사용) 모듈테스트가 편하다는 점인데
C#.NET 의 특징이긴하다. 근데 진짜 좋은지를 피부로 못느끼겠음.
한마디로 이런 방식은 안드로이드자바를 C#.NET의 WPF MVVM 패턴화 시킨 것
C#이 더 좋다는 뜻인데.
'Android' 카테고리의 다른 글
리스트 선택 : DialogFragment + ViewPager + 리스너연결 (0) | 2019.04.19 |
---|---|
BottomNavigationView 아이콘 사이즈 수정법 (태블릿 대응) (0) | 2018.10.19 |
리사이클러뷰 리스트 바인딩 문제 (0) | 2018.07.27 |
BLE 통신 개념 + 통신 과정 + Notification 설정 (9) | 2018.06.21 |
GridLayoutManager + Spacing (0) | 2017.11.20 |