Ile działań vs fragmentów?

185

Wprowadzenie:

Podstawowy wzorzec „Fragment Tutorial” wygląda mniej więcej tak:

  1. Na tablecie miej listę po lewej, szczegóły po prawej.
  2. Oba są Fragmentsi oba znajdują się w tym samym Activity.
  3. Na telefonie miej listę Fragmentw jednym Activity.
  4. Uruchom nowy Activityze szczegółami Fragment.

(np. API 3.0 Fragments API autorstwa Dianne Hackborn i Przewodnik API Fragments API )

Na obu urządzeniach funkcjonalność znajduje się w Fragments. (prosty)

Na tablecie cała aplikacja to 1Activity , na telefonie jest ich wieleActivities .


Pytania:

  • Czy istnieje powód, aby podzielić aplikację telefonu na wiele Activities?

Jednym z problemów związanych z tą metodą jest to, że powielasz dużo logiki na głównym tablecie Activityi na osobnym telefonie Activities.

  • Czy nie byłoby łatwiej zachować model 1 działania w obu przypadkach przy użyciu tej samej logiki włączania Fragmentsi wyłączania (przy użyciu innego układu)?

W ten sposób większość logiki znajduje się w Fragmentssobie, a Activitykodowanie jest tylko jedno .

Przeczytałem też o tym ActionBarSherlock, że wydaje się, że działa najlepiej Fragmentszamiast Activities(ale jeszcze z tym nie pracowałem).

Czy samouczki są nadmiernie uproszczone, czy też pominąłem coś ważnego w tym podejściu?


Wypróbowaliśmy oba podejścia z powodzeniem w biurze - ale mam zamiar rozpocząć większy projekt i chcę, aby wszystko było jak najłatwiejsze.

Niektóre linki do powiązanych pytań:


Aktualizacje

Zacząłem nagrodę od pytania - wciąż nie jestem przekonany, dlaczego muszę powielać logikę aplikacji w aktywności na tablecie i każdej aktywności na telefonie.

Znalazłem także ciekawy artykuł od facetów z Square, który warto przeczytać:

Richard Le Mesurier
źródło
38
+1 za niesamowite i dobrze napisane pytanie.
Siddharth Lele,
to jest coś, co bardzo mnie dzisiaj boli, obecnie pracuję nad aplikacją, która zawiera wiele fragmentów i będzie dostępna zarówno na telefonie, jak i tablecie, szukam pośredniej drogi, ale jeszcze jej nie znalazłem ...
Nixit Patel,
1
Szczerze mówiąc nie mam na myśli urazy, ale myślę, że akceptujesz to, co chciałeś usłyszeć, a nie prawdziwą odpowiedź. Google nie zaleca odpowiedzi Scuba, a post na blogu, który lubiłem wyjaśniać, dlaczego.
pjco
1
@pjco W szczególności nie zgadzam się z posiadaniem onItemSelected()metody w ćwiczeniu . W mojej „prawdziwej” aplikacji mam wiele list i podlist. Ten wzorzec sugeruje, że moja Aktywność na karcie musi mieć onItemSelected()metodę obsługi każdej z list. Co więcej, działania telefoniczne muszą mieć tę samą logikę zduplikowaną w każdym z nich. IMHO o wiele lepiej jest umieścić logikę wyboru przedmiotu w każdym fragmencie - nie ma duplikacji i wolę ten sposób strukturyzacji kodu. Mam nadzieję, że to pomoże
Richard Le Mesurier,
2
Obecnie jestem zawieszony na tym dylemacie w pracy. Fragmenty ładują się znacznie szybciej niż uruchamianie nowych działań, więc zacząłem wdrażać architekturę pojedynczych działań. Natknąłem się jednak na problem polegający na tym, że nie mogę znaleźć dobrego sposobu na wsparcie konfiguracji wielu fragmentów bez robienia czegoś hackującego. Zobacz to pytanie .
theblang

Odpowiedzi:

41

Zgadzam się, że samouczki są bardzo uproszczone. Po prostu wprowadzają, Fragmentsale nie zgadzam się z sugerowanym wzorem.

Zgadzam się również, że powielanie logiki aplikacji w wielu działaniach nie jest dobrym pomysłem (patrz Zasada DRY na Wikipedii ).


Wolę wzór używany przez ActionBarSherlockaplikację Fragments Demo ( pobierz tutaj i kod źródłowy tutaj ). Demo, które najbardziej odpowiada samouczkowi wspomnianemu w pytaniu, to „Layout” w aplikacji; lub FragmentLayoutSupportw kodzie źródłowym.

W tym demo logika została przeniesiona z Activityi do Fragment. W TitlesFragmentrzeczywistości zawiera logikę zmiany Fragmentów. W ten sposób każde działanie jest bardzo proste. Duplikowanie wielu bardzo prostych działań, w których nie ma żadnej logiki, sprawia, że ​​jest to bardzo proste.

Umieszczając logikę we Fragmentach, nie trzeba pisać kodu więcej niż jeden raz ; jest dostępny bez względu na to, w którą czynność jest umieszczony Fragment. To sprawia, że ​​jest to bardziej wydajny wzór niż ten sugerowany w podstawowym samouczku.

    /**
    * Helper function to show the details of a selected item, either by
    * displaying a fragment in-place in the current UI, or starting a
    * whole new activity in which it is displayed.
    */
    void showDetails(int index)
    {
        mCurCheckPosition = index;

        if (mDualPane)
        {
            // We can display everything in-place with fragments, so update
            // the list to highlight the selected item and show the data.
            getListView().setItemChecked(index, true);

            // Check what fragment is currently shown, replace if needed.
            DetailsFragment details = (DetailsFragment) getFragmentManager()
                .findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index)
            {
                // Make new fragment to show this selection.
                details = DetailsFragment.newInstance(index);

                // Execute a transaction, replacing any existing fragment
                // with this one inside the frame.
                FragmentTransaction ft = getFragmentManager()
                    .beginTransaction();
                ft.replace(R.id.details, details);
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }

        }
        else
        {
            // Otherwise we need to launch a new activity to display
            // the dialog fragment with selected text.
            Intent intent = new Intent();
            intent.setClass(getActivity(), DetailsActivity.class);
            intent.putExtra("index", index);
            startActivity(intent);
        }
    }

Kolejną zaletą wzoru ABS jest to, że nie kończy się na działaniu tabletu zawierającym dużo logiki, a to oznacza, że ​​oszczędzasz pamięć. Wzorzec samouczka może prowadzić do bardzo dużej głównej aktywności w bardziej złożonej aplikacji; ponieważ musi obsłużyć logikę wszystkich fragmentów, które zostaną w nim umieszczone w dowolnym momencie.

Ogólnie rzecz biorąc, nie myśl o tym jako o konieczności korzystania z wielu działań. Pomyśl o tym jako o możliwości podzielenia kodu na wiele fragmentów i oszczędzania pamięci podczas ich używania.

Stephen Asherson
źródło
dzięki za wyczerpującą odpowiedź - obejrzałem dema ABS i myślę, że jest tam dużo dobrego kodu. Zamiast tego spróbuję przenieść większość mojej logiki do Fragmentów
Richard Le Mesurier,
Aplikacja demonstracyjna została przeniesiona tutaj: play.google.com/store/apps/…
Philipp E.
Myślę, że opisany przez ciebie wzorzec pochodzi z oryginalnego przykładowego kodu Google: android-developers.blogspot.com/2011/02/... Myślę, że ActionBarSherlock właśnie przeniósł kod demonstracyjny Google, aby użyć klas ABS.
Dan J
17

Myślę, że jesteś na dobrej drodze. (I tak, samouczki są nadmiernie uproszczone).

W układzie tabletu można użyć pojedynczego działania i zamieniać fragmenty (w wielu oknach). W układzie telefonu możesz użyć nowej Aktywności dla każdego Fragmentu.

Tak jak:

wprowadź opis zdjęcia tutaj

Może się to wydawać dużo dodatkowej pracy, ale używając wielu działań na telefony, włączasz podstawowy cykl życia działania i przekazywanie celowe. Pozwala to również frameworkowi na obsługę wszystkich animacji i stosu.

Aby zmniejszyć kod, możesz użyć BaseActivityi rozszerzyć od tego.

Więc jeśli użytkownik ma tablet, którego byś użył MyMultiPaneFragActivitylub coś podobnego. To działanie jest odpowiedzialne za zarządzanie wywołaniami zwrotnymi z fragmentów i kierowaniem zamiarów do odpowiedniego fragmentu (np. Zamiaru wyszukiwania)

Jeśli użytkownik ma telefon, możesz użyć zwykłego działania z bardzo małym kodem i rozszerzyć go MyBaseSingleFragActivitylub coś podobnego. Działania te mogą być bardzo proste, 5-10 linii kodu (może nawet mniej).

Trudna część to rutowanie zamiarów i tak dalej. * (Edycja: zobacz więcej poniżej).

Myślę, że powodem tego jest zalecany sposób oszczędzania pamięci i zmniejszenia złożoności i sprzężenia. Jeśli wymieniasz Fragmenty, FragmentManagerzachowuje odniesienie do tego Fragmentu dla stosu wstecznego. Upraszcza również to, co powinno być „uruchomione” dla użytkownika. Ta konfiguracja oddziela także widoki, układ i logikę Fragmentu od cyklu życia Aktywności. W ten sposób Fragment może istnieć w pojedynczym działaniu, obok innego fragmentu (dwupanelowego) lub w trzypantowym Działaniu itp.

* Jedną z korzyści regularnego routingu celowego jest to, że możesz uruchomić działanie jawnie z dowolnego miejsca na tylnym stosie. Jednym z przykładów może być w przypadku wyników wyszukiwania. (MySearchResults.class).

Przeczytaj tutaj, aby uzyskać więcej:

http://android-developers.blogspot.com/2011/09/preparing-for-handsets.html

Może to być trochę więcej pracy z góry, ponieważ każdy fragment musi dobrze działać w różnych działaniach, ale zwykle się opłaca. Oznacza to, że możesz używać alternatywnych plików układu, które definiują różne kombinacje fragmentów, zachowują modułowy kod fragmentu, upraszczają zarządzanie paskiem akcji i pozwalają systemowi obsługiwać cały tylny stos.

pjco
źródło
Czy przewaga MySearchResults - sugerujesz inny sposób reagowania na ten zamiar w zależności od telefonu lub tabletu - dlaczego jest to lepsze niż posiadanie pojedynczego działania, które reaguje w obu przypadkach? Sugerujesz, że na tablecie nie ma regularnego zamierzonego routingu - więc i tak musisz rozwiązać problem z tabletem. Dlaczego nie skorzystać z tego rozwiązania również na słuchawce?
Richard Le Mesurier,
Zaletą jest to, że Twój kod tabletu może oczekiwać, że będzie kierował do wielu paneli. Czasami będziesz chciał zmienić wiele paneli w jednym celu. Na przykład wyniki wyszukiwania po lewej stronie z detaliami pierwszego elementu w większym okienku po prawej stronie. Ten kod nie byłby przenośny dla jednego układu.
pjco,
Dlaczego można przełączać fragmenty, gdy jest ich wiele, ale jeśli widoczny jest tylko jeden fragment, nie mogę przełączać się na inny fragment?
Richard Le Mesurier,
Nie jestem pewien, czy rozumiem, co masz na myśli, ale aby wyjaśnić mój komentarz powyżej: Czasami możesz chcieć zmienić więcej niż 1 fragment w tym samym czasie w układzie wielu fragmentów. Wymaga to kodu, aby zmienić 2 fragmenty, których nie używałbyś ponownie w układzie pojedynczego fragmentu
pjco
Nie ma za co :) Proszę głosować lub zaakceptować, jeśli uważasz, że odpowiedź jest pomocna
pjco
6

Oto odpowiedź Reto Meiera na ten sam temat, zaczerpnięta z filmu z kursu Podstawy Androida w Udacity .

Istnieje wiele powodów, dla których lepiej byłoby podzielić swoją aplikację na różne działania.

  • Posiadanie pojedynczej aktywności monolitycznej zwiększa złożoność kodu, utrudniając czytanie, testowanie i konserwację.
  • Znacznie utrudnia tworzenie filtrów zamiarów i zarządzanie nimi.
  • Zwiększa ryzyko ścisłego połączenia niezależnych elementów.
  • Znacznie zwiększa ryzyko wprowadzenia zagrożeń bezpieczeństwa, jeśli pojedyncze działanie obejmuje zarówno informacje wrażliwe, jak i informacje, które można bezpiecznie udostępniać.

Dobrą zasadą jest tworzenie nowej aktywności za każdym razem, gdy zmienia się kontekst. Na przykład wyświetlanie innego rodzaju danych i przechodzenie od przeglądania do wprowadzania danych.

Aditya Naique
źródło
co ciekawe tytuł filmu brzmi „Dlaczego nie używamy tylko fragmentów”
Richard Le Mesurier
jest to dobre podejście,
mam do
4

Jednym z problemów związanych z tą metodą jest to, że powielasz dużo logiki w głównym działaniu tabletu oraz w osobnych działaniach telefonicznych.

We wzorcu wzorcowym istnieją dwie czynności. Jeden pokazuje oba fragmenty na większych ekranach i tylko fragment „wzorcowy” na mniejszych ekranach. Drugi pokazuje fragment „szczegółów” na mniejszych ekranach.

Twoja logika szczegółowa powinna być związana z fragmentem szczegółowym. W związku z tym nie występuje powielanie kodu związane z logiką szczegółów między działaniami - działanie szczegółowe wyświetla tylko fragment szczegółów, być może przekazując dane z Intentdodatkowego.

Przeczytałem również o ActionBarSherlock, że wydaje się, że najlepiej działa z Fragmentami zamiast Aktywności (ale jeszcze z nim nie pracowałem).

ActionBarSherlock nie ma więcej wspólnego z fragmentami niż natywny pasek akcji, ponieważ ActionBarSherlock jest jedynie backportem natywnego paska akcji.

CommonsWare
źródło
Jakie są twoje przemyślenia na temat pojedynczego działania?
theblang
@mattblang: Dopóki nawigacja jest prawidłowa, nie ma z tym problemu.
CommonsWare
1
Próbowałem refaktoryzacji do architektury z pojedynczym działaniem, ponieważ zamiana fragmentu jest o wiele szybsza niż uruchomienie nowej aktywności z tym samym fragmentem. Czuję się, jakbym wpadł w zbyt wiele problemów, w ten sposób . Większość przykładów, które znajduję w Internecie, szczególnie w przypadku konfiguracji z wieloma fragmentami, takich jak master-detail, nie używa jednej aktywności. Więc mam trochę dylematu.
theblang
0

Odnosząc się do pierwszego pytania „Czy istnieje powód, aby podzielić aplikację telefonu na wiele działań?” - Tak. sprowadza się to po prostu do dostępnej przestrzeni, tablet daje więcej miejsca dla programistów, umożliwiając programistom umieszczenie większej liczby elementów na jednym ekranie. Android informuje nas, że Działania mogą zapewnić ekran . Tak więc, co możesz zrobić z 1 dużym ekranem na tablecie, jest czymś, co może wymagać podziału na wiele ekranów w telefonie, ponieważ nie ma wystarczającej ilości miejsca na wszystkie fragmenty.

EFlisio
źródło
Zdanie pierwsze - „Działanie to komponent aplikacji, który zapewnia ekran, z którym użytkownicy mogą wchodzić w interakcje, aby coś zrobić”. I widzisz błąd w moim pierwotnym oświadczeniem, nie chciałam umieścić „to kolejny ekran”
EFlisio