Pull to refresh

Comments 15

Давайте не будем писать 100500 фрагментов, давайте лучше напишем 100500 кастомных лэйаутов.
На сколько легко будет передать ItemListView из примера, если потребуется перейти со старого ListView на новый RecyclerView?
getChildAt(0), getChildAt(1) это шедевр. Дотаточно по неосторожности добавить в xml разметку еще один элемент что бы код сломался.
onFinishInflate(), listViewAttached() — те же самые колбэки жизненного цикла, только уже у View. Попробуйте нарисовать самостоятельно такой же граф жизненного цикла для View, как приводится для фрагментов, проще он будет не намного.
Что если мой ListFragment использует разные лэйауты для sw-600dp и sw-700dp, но по коду ничем не отличается? Сделать классы ItemListView600 и ItemListView700?
При всем моем восхищении чуваками из squareup, спасибо, но нет.
Что если мой ListFragment использует разные лэйауты для sw-600dp и sw-700dp, но по коду ничем не отличается?

Просто создать разные разметки так же как и для фрагментов.
getChildAt(0), getChildAt(1) это шедевр.

В статье всё-таки приводится пример, а не production-code. Да, такой код легко ломается, лучше искать view через findViewById().
На сколько легко будет передать ItemListView...

Извините, немного не понял вас. Куда его нужно передавать?

… если потребуется перейти со старого ListView на новый RecyclerView?

Перейти с ListView на RecyclerView будет в любом случае непросто, вне зависимости от того, используете вы фрагменты или нет. Опять-таки, уточните, пожалуйста, что вы имели в виду.

Попробуйте нарисовать самостоятельно такой же граф жизненного цикла для View, как приводится для фрагментов, проще он будет не намного.

Тот граф, что я нашёл, выглядит гораздо проще чем у фрагментов. Покажете более полный?
Перейти с ListView на RecyclerView будет в любом случае непросто, вне зависимости от того, используете вы фрагменты или нет

Смотрите, если я использую фрагмент, то при переходе к RecyclerView поменяется layout-файл фрагмента и внутри фрагмента поменяется всё, что касается ListView. У нас появится новый адаптер, новый RecyclerView и новый OnClick-колбэк. Но это всё будет внутри фрагмента. Все, кто использовал мой фрагмент вообще не заметят никакой разницы при переходе на RV.
В статье же, автор то ли схитрил, то ли поленился показать как заполняется MyListAdapter. Если MyListAdapter выходит за рамки ItemListView, то при переходе да RV придется заменить и его адаптер во всех контейнерах которые его используют. Если же данные в ItemListView попадают через его гипотетический метод ItemListView.showData(items), а оттуда уже в адаптер, то уже не все так плохо. Правда все равно остается вероятность, что кто-то не воспользуется вашим контрактным методом showData(), а установит в ItemListView свой адаптер.
Точно такая же история с OnItemClickListener. В статье автор взял и просто напрямую написал внутри своей ItemListView MainActivity activity = (MainActivity) getContext(). Это что, опять "пример, а не production-code"? По хорошему или родительский контейнер должен установить в ItemListView колбэк на клик (и тогда придется переписывать все контейнеры при миграции на RecyclerView.OnClickLisetener()) или ItemListView должен дергать у контейнера onItemClicked, который, разумеется должен быть скрыт за интерфейсом как это делается для фрагментов. Да, наличие презентеров никак эту проблему не решает, т.к. все колбэки просто переносятся из View в Presenter.
Я надеюсь, я не сумбурно объяснил свои опасения
Да, спасибо за разъяснения, опасения и правда оправданные. Я вот сейчас посмотрел пример от Square, который использует Mortar, и в нём часть ваших претензий учтена: адаптер создаётся внутри ChatListView, а наружу торчит метод showConversations(), который принимает список чатов, и прокидывает их в адаптер. Ничто не мешает, правда, в текущей реализации установить свой адаптер, но можно эту ситуацию обойти как-нибудь вот так:

@Override
public final void setAdapter(ListAdapter adapter) {
    throw new UnsupportedOperationException("Use ChatListView#showConversations(List<Chat> chats) instead");
}

OnItemClickListener в примере тоже устанавливается через ChatListView.

Я статью перевёл не для того, чтобы оповестить всех о новой серебряной пуле, а чтобы показать на возможные альтернативы, которые тоже могут быть не лишены недостатков (сам я Flow/Mortar, признаюсь, пока что не использовал). В той же статье от BigNerdRanch, которую упоминали ниже, жаловались на большое количество boilerplate, которое получается при их использовании.
Вообще, чтобы совсем уж абстрагироваться, ItemListView должен не наследоваться от ListView напрямую, а реализовывать какой-нибудь интерфейс IItemListView, и содержать ListView внутри. Тогда клиенты не будут знать о его реализации ничего, и замена ListView на RecyclerView пройдёт относительно безболезненно.
P.S. Написал и сам тут же понял, какую глупость сморозил. Это же view, нам его потом инфлейтить нужно, поэтому такой финт не пройдёт.
Ага, а потом напишем в нем onCreateView(), и получим фрагмент :)
Это односторонний взгляд. Недавно был случай — попросили вместо фрагмента показать диалог, так вот это был головняк еще тот.
Flow — библиотека на любителя, но это не значит, что фрагменты хороши.
В другом UI фреймворке я бы просто сделал нужные компоненты и повторно их использовал как мне захочется, а в андроиде куча состояния, проверок, компонентов с разным жизненным циклом.
К картинке-графу жизненного цикла фрагмента тоже большая претензия, т.к. там намешано всё, кони, люди… Уже не раз обсуждалось, что onSaveInstanceState/onResoreInstanceState это не методы жизненного цикла, они могут быть вызваны совершенно в разных ситуациях и в разных местах жизненного цикла. Всё что от вас требуется — это сохранять состояния и возвращать состояние в них. У View между прочим тоже есть onSaveInstanceState() и onResoreInstanceState(), почему их нет на том графе, что Вы нашли, непонятно.
onPrepareOptionsMenu, onCreateOptionsMenu это вообще шаблонные методы и непонятно, почему эти 2 метода попали в этот граф, а десяток других шаблонных методов не попали.

Еще навскидку, в графе лайфцикла View не преведены onFinishTemporaryDetach(), onStartTemporaryDetach(), onVisibilityChanged(), onFinishInflate(), вероятно еще что-то
Тем, кто интересуется темой Mortar & Flow рекомендую изучить статью ребят из BigNerdRanch. Правда код примеров в ней еще год назад уже был устаревшим, поэтому детальный пример от Square.
Так же на Droidcon Berlin выступал Торбен Примке с этой темой: его доклад и сэмпл. И пример использования Mortar-Flow c Dagger2
А кто-нибудь знает пример какого-либо приличного приложения, написанного на Mortar+Flow? Может кто-нибудь сам использует?
упомянутый мной Торбен Примке в своем докладе говорит о том, что они свои приложения пишут на нем.
Я в свои сторонних проектах тоже использую
Все эти фрагменты, которые наполовину View, наполовину Activity появились не просто так. При переиспользовании одних и тех же View в разных activity приходилось постоянно дублировать прокидывание разных колбэков жизненного цикла вьюшкам. Посмотрите на класс Webview, который появился гораздо раньше фрагментов и увидите у него webview.onPause(), webview.onResume().
Представьте, что вы написали свой видеоплеер MyVideoPlayer и добавили его в Activity1. Теперь у вас появилось требование останавливать видео, если экран с видео перекрывается другим экраном. в Activity1.onStop() я напишу myVideoPlayer.stop(). Потом у меня появляется Activity2 с таким же плеером и таким же требованием. Опять переопределять onStop()? Конечно нет. Создавать общую ViedeoPlayerActivity? Ну можно, если Activity1 и Activity2 это позволяют (все помнят, что в java нет множественного наследования). Я могу создать VideoFragment и это решит все мои проблемы. Как это будут решать ребята из squareup?
а в чем разница такого же синглтона для того чтобы менеджить колбэки и запросы с интернета? тот же service или application? переворот экрана всегда была головной болью что Activity, что Fragment, что custom view жизненный цикл ведь никто не отменял
Sign up to leave a comment.

Articles