Шпаргалка или Must have для андроид разработчика

в 15:50, , рубрики: android, butterknife, dagger 2, multidex, retrofit 2, Разработка под android

Статья была создана для разработчиков которые желают найти новые инструменты и библиотеки для дальнейшего упрощения рутинной жизни.

Итак, начнем.

Butterknife

Библиотека была разработана компанией Square и сразу же прижилась у разработчиков. ButterKnife был создан на замену findViewById для того чтобы уменьшить и без того раздутые activity:

View someView = (View) findViewById(R.id.someView)

Вы только посмотрите какая длинная строка! А если это поле класса — то это целых две строки:

View someView; //Первая строка
...
@Override 
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        someView = (View) findViewById(R.id.someView); //Вторая строка
}

А теперь перейдем к ButterKnife. Вот простой пример кода с ButterKnife:

    @BindView(R.id.someView1) View view1;
    @BindView(R.id.someView2) View view2;
    @BindView(R.id.someView3) View view3;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this); //Важная строка
    }

Все очень просто: с помощью аннотации @BindView мы говорим какая вьюха нам нужна, и потом главное не забыть про ButterKnife.bind(this);(Так делать нужно в активити, для других мест вроде holder или fragment это делают немного по-другому. Смотрите здесь.

Как добавить к проекту?

Gradle(app module):

  compile 'com.jakewharton:butterknife:8.5.1'
  apt 'com.jakewharton:butterknife-compiler:8.5.1'
или annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' с jack

Retrofit 2

Компания Square создала не только ButterKnife, но и много других прекрасных библиотек без которых многие разработчики не представляют свою жизнь. Одна из таких библиотек Retrofit 2.

Она была создана для того чтобы упростить работу с REST API. Раньше чтобы сделать запрос приходилось воротить горы кода, но сейчас все по-другому. Итак, как же сделать запрос?

Добавить в gradle(app module):

    compile 'com.google.code.gson:gson:2.7'
    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
//если использовать  rxJava то еще и 
    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

Сначала берут сайт для конвертации с json в pojo вроде этого и копируют все классы которые сгенерировались в AndroidStudio:

image

Потом создают интерфейс(Я использую retrofit вместе с RxJava):

public interface IWeatherProvider{
    @GET("/premium/v1/weather.ashx")
    Observable<Model> getWeather(@QueryMap Map<String, String> map);
}

В QueryMap бросают query параметры(например api key). Хотя можно вместо @QueryMap использовать просто Query но тогда для каждого параметра надо прописать свой query.

После этого:

Retrofit retrofit =  Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(Constants.WEATHER_BASE_URL)
                .build();
...
retrofit.create(IWeatherProvider);

Потом нужно за полнить параметры данными:


        HashMap<String, String> mapJson = new HashMap<>();
        mapJson.put("key", Constants.WEATHER_API_KEY);
        mapJson.put("q", latitude + "," + longitude);
        mapJson.put("num_of_days", "14");
        mapJson.put("date", "today");
        mapJson.put("format", "json");

И вызвать iweatherProvider.getWeather(mapJson);

И наконец:

new CompositeDisposable().add(weatherProvider
                .observeOn(Schedulers.newThread())
                .subscribeOn(Schedulers.io())
                .subscribe(onNext, onError));

В случае если вы не используете RxJava замените в интерфейсе Observable на Call и сделайте

iweatherProvider.getWeather(mapJson).enqueue(callback);

Dagger 2

Создан гуглом. Помогает реализовать паттерн Dependency Injection. С помощью Dagger'а можно круто структурировать проект, что очень хорошо сказывается на читабельности кода и помогает в тестировании(кстати использовать retrofit вместе с dagger'ом само наслаждение). Смысл в том что все классы хотят работать уже с готовыми данными, им нужно лишь получить их, и что-то с ними сделать. Но кто-то должен предоставлять данные. Эту роль на себя берет dagger. Основа Dagger это компоненты, вот один из них:

@Component(modules = {WeatherInfoTaskModule.class})
public interface RetrofitComponent {
    void inject(MainActivity activity);
}

Все компоненты состоят из модулей, в одном компоненте может быть несколько модулей, вот пример модуля:

@Module
public class WeatherInfoTaskModule {

    @Provides
    Gson provideGson() {
        Log.d(TAG, "gson");
        return new GsonBuilder().create();
    }

    @Provides
    IWeatherProvider provideWeather(Retrofit retrofit) {
        Log.d(TAG, "weather");

        return retrofit.create(IWeatherProvider.class);
    }

    @Provides
    Retrofit provideRetrofit(Gson gson) {
        Log.d(TAG, "retrofit");

        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .baseUrl(Constants.WEATHER_BASE_URL)
                .build();
    }
}

Внутри модулей находятся функции с аннотацией Provides, как следует из аннотации они поставляют данные. В основном эти функции делят на модули по смыслу(к примеру геолокация). И здесь возникает логичный вопрос, ну как это использовать?

Очень просто. В вашей активити помечаете поля которые должны получить данные аннотацией Inject( @Inject IWeatherProvider mWeatherProvider;). Потом создаете свой Application класс:

public class App extends Application {
    private static RetrofitComponent component;
    @Override
    public void onCreate() {
        super.onCreate();
        component = DaggerRetrofitComponent.create();
    }

    public RetrofitComponent getComponent() {
        return component;
    }
}

В MainActivity в OnCreate сделайте следущее:

 
 @Inject IWeatherProvider mWeatherProvider;
...
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((App) getApplicationContext()).getComponent().inject(this);
        }

P.S. Не забудьте добавить App класс в манифест.

В gradle(app):

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'android-apt'
dependencies{
    compile 'com.google.dagger:dagger:2.7'
    apt 'com.google.dagger:dagger-compiler:2.7'
}

в gradle(project module):

        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

Но что если одной из функций на вход тоже нужны данные? В таком случае dagger пробегается по компоненту в поисках функции которая возвращает необходимый класс или тип данных, и когда находит — вызывает.

Что будет если я поменяю название функции? Dagger'у абсолютно все равно на название, его интересуют лишь сигнатуры, поэтому на работу это не влияет.

Студия подсвечивает класс DaggerRetrofitComponent красны. Что делать? Dagger работает на кодогенерации поэтому в таком случает стоит просто сделать rebuild.

Multidex

Рано или поздно разработчик сталкивается с проблемой в 65 тысяч методов. Но начнем сначала. Когда вы хотите установить приложение на телефон вам нужен apk файл. Основа любого apk файла dex файл. Dex файл — это ваши java классы собранные в один файл. Но у dex файла есть ограничение в 65 тысяч методов. И большая часть приложений превышает этот лимит и получает exception при сборке. Для таких случаев создан multidex. В gradle(app module) добавляете:

...
defaultConfig {
...
        multiDexEnabled true
...
 }
...
 compile 'com.android.support:multidex:1.0.1'

Создаете App класс наследований от MultiDexApplication и прописываете его в манифесте:

public class App extends MultiDexApplication {

    @Override
    public void onCreate() {
        MultiDex.install(this);
        super.onCreate();
    }

Пост вышел длинным, но зато я надеюсь что хот как-то объяснил. А какими библиотеками пользуетесь вы?

Автор: vlad2711

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js