Android-монстрик по имени FunLib

в 17:15, , рубрики: Без рубрики

Android монстрик по имени FunLibПривет, меня зовут Юра. И я, как и многие из вас, программист. Как известно, программисты — это не просто разработчики ПО, но создатели. Но, к сожалению, в повседневной работе сложно создавать что-то новое (особенно, когда ты занят мобильной разработкой). И это часто порождает желание собрать своего Франкенштейна (ну или велосипед, если вам так хочется), хотя бы в свободное время. Например, мне всегда хотелось сделать своего Франкенштейна, который будет выполнять за меня основную рутинную работу в Android-приложении.

И вот у меня недавно, наконец, нашлось свободное время на это дело (прим. автора: здесь можно просто за меня порадоваться)! Почитав разные статьи о том, что сейчас модно, или стало модным ещё много лет назад, я собрал для себя примерный список того, из чего будет состоять мой друг. И вот чему он у меня пока научился:

  • Ходить! Он ходит в интернеты, достаёт оттуда данные, и приносит к себе
  • Помнить! Если надо, он запомнит то, что взял в интернетах, может даже сперва обработать эти данные
  • И вообще — выполнять несколько задач одновременно! Причём, не надо заморачиваться над тем, что вдруг наш монстрик решит, например, покувыркаться

Сколько разных элементов мне пришлось свалить в одну кучу, чтоб мой монстрик, по имени FunLib ожил! Тут собрались такие звёзды, как retrofit, eventbus, jobqueue… Но давайте по-порядку! Итак, кто за что отвечает в моём детище:

Хождение в интернет

В интернет мы ходим, используя Retrofit+OkHttp. Это позволяет делать всю работу быстро, аккуратно и при поддержке большого комьюнити. Согласитесь, очень удобно делать запрос на сервис примерно таким способом:

public interface GithubApi {
    @GET("/search/repositories?sort=stars&order=desc")
    SearchResult search(@Query("q") String query);
}

И ведь как круто получается, прям по-евангелистки! Ведь разработка реально ведётся не на уровне реализации, а, буквально, на уровне интерфейса! Вообще, очень много чего можно добавить в запрос, по разному настроить его. Но т.к. это не сама суть статьи, оставлю это на ваше самостоятельное изучение. Ну или было бы здорово, если бы кто-нибудь написал, как он круто использует эти библиотеки, особенно, если его ходы не тривиальны и не освещены в офф. гайде.

Память в БД

За память у него отвечает ORMLite. Как говорится, на вкус и цвет все фломастеры разные. Мне это решение нравится больше всего. Особенно, к плюсам этой библиотеки я отношу вот что:

  • Из базы можно получать уже готовые объекты, а не сырой набор данных(даже с данными по вторичным ключам)
  • Можно получать крусор, выполняя ORM запрос
  • Можно получать курсор, выполняя обычный sql-запрос, со всеми вытекающими возможностями
  • Такое решение наверняка будет легко понятно каждому, кто будет в будущем сопровождать/читать ваш код

Здесь, как обычно — аннотируем нужные классы и поля как @DatabaseTable и @DatabaseField, соответственно. После чего спокойно можем сложить, или, если надо, достать, данные в БД:

private void saveRepositories(List<Repository> repositories) throws SQLException {
    Dao<User, ?> userDao = getDbHelper().getDao(User.class);
    Dao<Repository, ?> repositoryDao = getDbHelper().getDao(Repository.class);

     for (Repository repository : repositories) {
        userDao.createOrUpdate(repository.getOwner());
        repositoryDao.createOrUpdate(repository);
    }
}

PS: к сожалению, пока FunLib не умеет удобно нотифаить лоадеры по URI… Да и его активити с фрагментами не предоставляют функционало для удобной работы с лоадерами, но всё в ваших руках! Пулл-рекввесты ждут вас. Ну или ждите, пока я это сделаю :P

Мозги для параллельной работы

Для этого немаловажного процесса был выбран инструмент под названием Priority Job Queue. Почему же мы не сделали свой собственный сервис? Да всё просто — мне было интересно использовать эту библиотеку =) Да и манифест остаётся чист. И, что не мало важно, это решение довольноприемлемо аккуратно вписывается в нашу Центральную Нервную Систему(чуть ниже про неё сказано). Но мы с FunLib сели, подумали, и решили, что тот Job, от которого команда Path предлагает нам наследоваться, слишком монструозен. Мне будет тяжело давать моему малышу какие-нибудь команды. Ну или ему будет не так просто их понять. Поэтому был сделан карапуз по имени FunJob, который умеет просто выполнить нужную нам работу в методе public abstract T doJob() throws Throwable.

Пример работы. Внимание! Монстр опасен! Заглядывать только отчаявшимся смельчакам!

public class SearchJob extends FunJob<List<Repository>> {
    private String mQuery;

    public SearchJob(int id, String query) {
        super(id);
        mQuery = query;
    }

    @Override
    public List<Repository> doJob() throws Throwable {
        SearchResult searchResult = ((GithubApi) getApi()).search(mQuery);

        List<Repository> repositories = searchResult.getRepositories();

        return repositories;
    }
}

Центральная Нервная Система или просто DI

Для такой важной задачи, как доставка БД, интернета, и прочей информации в мозг и обратно к телу роботика, был использован компонент по имени Dagger, реализующий Dependency Injector. Благо, наши мозги умеют делать инъекцию в Job тогда, когда Job уже готов выполняться! Поэтому FunJob, когда делает свою работу, уверенно может обращаться к БД, к API, и вообще знает, что он — это он! Ведь это так важно связать мозги с телом!

А для отправки команды от мозгов к телу была использована штука под названием EvenBus. Изначально хотел использовать Otto, но, по непонятным причинам FunLib его невзлюбил, и я быстро отказался от него. Ну ничего — EventBus тоже отлично справляется со своей задачей! Тело всегда вовремя получает нужные команды!

Ready Steady Go!

На этом пока я решил сделать привал, завершить свой рассказ и получить от вас фитбэк. И уже после этого я продолжу дальше развивать моего кроху.

В примере вы можете отчётливо увидеть, как управлять работой FunLib — всего-то нужно:

  • наследоваться от FunApp, прописать в нём путь до API, интерфейс, работающий с API и ваш класс DbHelper
  • наследоваться от FunActivity/FunFragment, а там уже удобно стартовать работу, получать доступ к API и БД
  • сделать то, что вам нужно! ;)

Постскриптум

Возможно, прочитав про лоадеры, вы подумаете, что я, наконец, решу прикрутить к приложению ContentProvider. Но нет, этого делать я не планирую, т.к. думаю не спроста в офф. гайде написано: You don't need to develop your own provider if you don't intend to share your data with other applications. В моей практике ещё не приходилось делать такого приложения, которые бы предоставляло данные другим приложениям. И не надо из-за этого кидать в меня помидорами! Всем нам разные задачи попадаются.

Так же пока печалит то, что нужно самостоятельно следить за тем, какой ID для FunJob был выставлен. Но ничего — это будет исправлено, и это станет очередной вкусняшкой!

Кто пропустил ссылку на репозиторий, ловите: https://github.com/senneco/FunLib

Встретимся в комментах и в пулл-реквестах :D

Автор: senneco

Источник


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


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