package com.patloew.countries.ui.base; import android.databinding.DataBindingUtil; import android.databinding.ViewDataBinding; import android.os.Bundle; import android.support.annotation.CallSuper; import android.support.annotation.ColorRes; import android.support.annotation.DimenRes; import android.support.annotation.IntegerRes; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.v7.app.AppCompatActivity; import com.patloew.countries.BR; import com.patloew.countries.CountriesApp; import com.patloew.countries.injection.components.ActivityComponent; import com.patloew.countries.injection.components.DaggerActivityComponent; import com.patloew.countries.injection.modules.ActivityModule; import com.patloew.countries.ui.base.view.MvvmView; import com.patloew.countries.ui.base.viewmodel.MvvmViewModel; import com.patloew.countries.ui.base.viewmodel.NoOpViewModel; import com.squareup.leakcanary.RefWatcher; import javax.inject.Inject; import io.realm.Realm; /* Copyright 2016 Patrick Löwenstein * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ------- * * FILE MODIFIED 2017 Tailored Media GmbH * */ /* Base class for Activities when using a view model with data binding. * This class provides the binding and the view model to the subclass. The * view model is injected and the binding is created when the content view is set. * Each subclass therefore has to call the following code in onCreate(): * activityComponent().inject(this); * setAndBindContentView(R.layout.my_activity_layout, savedInstanceState); * * After calling these methods, the binding and the view model is initialized. * saveInstanceState() and restoreInstanceState() methods of the view model * are automatically called in the appropriate lifecycle events when above calls * are made. * * Your subclass must implement the MvvmView implementation that you use in your * view model. */ public abstract class BaseActivity<B extends ViewDataBinding, V extends MvvmViewModel> extends AppCompatActivity { // Inject a Realm instance into every Activity, since the instance // is cached and reused for a thread (avoids create/destroy overhead) @Inject protected Realm realm; protected B binding; @Inject protected V viewModel; @Inject RefWatcher refWatcher; private ActivityComponent mActivityComponent; @Override @CallSuper protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if(viewModel != null) { viewModel.saveInstanceState(outState); } } @Override @CallSuper protected void onDestroy() { super.onDestroy(); if(refWatcher != null) { refWatcher.watch(mActivityComponent); if(viewModel != null) { refWatcher.watch(viewModel); } } if(viewModel != null) { viewModel.detachView(); } binding = null; viewModel = null; mActivityComponent = null; if(realm != null) { realm.close(); } } protected final ActivityComponent activityComponent() { if (mActivityComponent == null) { mActivityComponent = DaggerActivityComponent.builder() .activityModule(new ActivityModule(this)) .appComponent(CountriesApp.getAppComponent()) .build(); } return mActivityComponent; } /* Sets the content view, creates the binding and attaches the view to the view model */ protected final void setAndBindContentView(@Nullable Bundle savedInstanceState, @LayoutRes int layoutResID) { if(viewModel == null) { throw new IllegalStateException("viewModel must already be set via injection"); } binding = DataBindingUtil.setContentView(this, layoutResID); binding.setVariable(BR.vm, viewModel); try { //noinspection unchecked viewModel.attachView((MvvmView) this, savedInstanceState); } catch(ClassCastException e) { if (!(viewModel instanceof NoOpViewModel)) { throw new RuntimeException(getClass().getSimpleName() + " must implement MvvmView subclass as declared in " + viewModel.getClass().getSimpleName()); } } } public int dimen(@DimenRes int resId) { return (int) getResources().getDimension(resId); } public int color(@ColorRes int resId) { return getResources().getColor(resId); } public int integer(@IntegerRes int resId) { return getResources().getInteger(resId); } public String string(@StringRes int resId) { return getResources().getString(resId); } }