Retrofit, Realm, Dagger Тестовое задание по Android за два часа
Retrofit 2, Realm 3, Dagger 2
Обычно в тестовой задаче требуется получить feed. Предусмотреть локальное добавление и удаление компонентов. Кэш. Использовать библиотеки для уменьшения количества кода.
Удаление по Swipe бонус.
Кэш можно реализовать на OkHttp но каждый раз придется его парсить и локального добавления не получится. Придется использовать контент провайдер с Sqlite или ORM.
Остановимся на ORM Realm. Realm написан на native и при правильном включении как плагин не значительно увеличит apk
Using the plugin we can now ship Realm as an AAR, as opposed to a JAR. We can also avoid including the annotation processor in the library and make it a standalone package. This means the your final APKs will not have to include the annotation processor, shaving a few kilobytes off your app
Retrofit известная библиотека от Square. Умеет подписывать результат на Observer, но на самом деле это не критично. Асинхронных запросов достаточно для большинства задач. Полезное применение Observer с Retrofit видится если надо фильтровать или преобразовать данные перед их использовании в Presenter.
Другая полезная библиотека от Square это Dagger. Dagger 2 использует генерацию кода в отличии от рефлексии в первой версии.
Теперь о Dagger. Есть много статей, но я небуду долго перечислять и копировать все подробно. Я пошагово покажу что и где надо определить. Это статья поможет понять начинающему как организовать структуру модулей и сделать иньекцию. Обьяснение на пальцах.
Чтобы создать в Activity обекты Retrofit и Realm нужны две строчки кода.
@Inject Retrofit retrofit; @Inject Realm mRealm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... ((App) getApplication()).getApplicationComponent().inject(this);
Это так называемая инъекция.
Теперь посмотрим на ApplicationComponent. Dagger генерит имена названий классов. Например DaggerApplicationComponent из ApplicationComponent, Realm из provideRealm,…
public class App extends Application { @Override public void onCreate() { super.onCreate(); WEB_SERVICE_BASE_URL = "http://" + AppUtils.getNetworkHost(this); mApplicationComponent = DaggerApplicationComponent.builder() .appModule(new AppModule(this)) .netModule(new NetModule(WEB_SERVICE_BASE_URL)) .realmModule(new RealmModule(this)) .build(); } public ApplicationComponent getApplicationComponent() { return mApplicationComponent; } }
Здесь мы создали наши модули. Точнее Dagger их создал за нас. Как происходит генерация?
Dager использует Анотацию
@Module public class RealmModule { @Provides @Singleton Realm provideRealm(RealmConfiguration realmConfiguration) { ...
Singleton provideRealm становится Inject Realm mRealm
Аналогичным образом происходит в модуле NetModule. Так происходит даже с параметрами в самом модуле:
Provides
Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
provideOkhttpClient и provideGson соответственно Gson, OkHttpClient
Далее В ApplicationComponent используем Component декларацию и перечисляем модули
@Singleton @Component(modules = {AppModule.class, NetModule.class, RealmModule.class}) public interface ApplicationComponent { void inject(MainActivity activity); }
Если понадобится использовать в другой Activity то надо добавить inject. Например для DetailActivity это выглядит так:
public interface ApplicationComponent { void inject(MainActivity activity); void inject(DetailActivity activity); }
Это распространяется на Fragments и Service так же.
Вернемся к Realm. Используемые объекты должны наследоваться от extends RealmObject. Их нельзя использовать напрямую для получения данных с Retrofit. Иначе ваш запрос просто зависнет.
В Activity:
mBooksViewAdapter = new BooksViewAdapter( mRealm.where(RealmBook.class).findAllSorted("id", Sort.ASCENDING), this);
В Adapter:
public BooksViewAdapter(RealmResults<RealmBook> books, OnStartDragListener dragStartListener) { this.mBooks = books;
Дальнейшая работа с объектом выглядит как с транзакциями Sqlite. Ниже пример добавления и удаления.
public void addBook(View view) { if (!mRealm.isInTransaction()) mRealm.beginTransaction(); RealmBook book = mRealm.createObject(RealmBook.class); book.setId("1" + Random(); book.setTitle("Terminator"); book.setLink("http;//rerer/rerer/trytry"); book.setPrice(12332d); mRealm.commitTransaction(); mBooksViewAdapter.notifyDataSetChanged(); } @Override public void onDeleted(int position, String id) { RealmBook realmBooks = mRealm.where(RealmBook.class).equalTo("id", id).findFirst(); if (realmBooks != null) { if (!mRealm.isInTransaction()) mRealm.beginTransaction(); realmBooks.deleteFromRealm(); mRealm.commitTransaction(); } }
Realm поддерживает события через интерфейс RealmChangeListener.
mBooks.addChangeListener(this);
Будет отрабатывать метод onChange если в выборке произошли изменения. Может быть полезно для обновления данных в Adapter.
@Override public void onChange(Object element) { notifyDataSetChanged(); }
Приводится только самые базовые вещи из библиотек Dagger и Realm. Retrofit не рассмотрен в текущей статье.
Возможно в следующих публикациях я расскажу о Clean Architecture. Популярный подход для проектирования больших приложений.
Конструктивная критика приветствуется!
ссылка на оригинал статьи https://habrahabr.ru/post/325172/
Добавить комментарий