2015-06-11 9 views
13

Mam pytanie dotyczące "właściwego programowania" w systemie Android.Podstawy Android Fragments: dlaczego? Czy to jest koncepcyjnie błędne?

Obecnie pracuję nad aplikacją przy użyciu fragmentów. Obejmuje dynamicznie dodawane fragmenty do działania, fragmenty zawyżone z XML, zagnieżdżone fragmenty z XML lub dynamicznie dodawane. Powiedzmy, trochę wszystkiego.

Pojęcie, na które koncentruje się to pytanie, to proces komunikacji z fragmentami. Tak, czytałem dokumenty i nie pierwszy raz próbuję używać fragmentów.

Zdrowy rozsądek (i docs) mówią, że jeśli Fragment chce mówić lub komunikować się z jego aktywnością, powinniśmy użyć interfejsu.

przykład:

TestFragment

public class TestFragment extends Fragment { 

    private TestFragmentInterface listener; 

    public interface TestFragmentInterface { 

     void actionMethod(); 

    } 


    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 

     if (getActivity() instanceof TestFragmentInterface) { 
      listener = (TestFragmentInterface) getActivity(); 
     } 

     // sending the event 
     if (listener != null) listener.actionMethod(); 
    } 

} 

działanie testowe

public class Test implements TestFragmentInterface { 

    @Override 
    public void actionMethod() { 
    .. 
    } 
} 

Wszystko tu dobrze.

Poprawia to ponowną użyteczność, ponieważ mój TestFragment w ten sposób może wchodzić w interakcję z dowolnym rodzajem Aktywności, biorąc pod uwagę, że Aktywność implementuje deklarowany przeze mnie interfejs.

Odwrotnie, działanie może wchodzić w interakcję z fragmentem, przytrzymując odnośnik i wywołując jego publiczne metody. Jest to również sugerowany sposób komunikacji fragmentacji z fragmentem, wykorzystujący działanie jako pomost.

To jest fajne, ale czasami wydaje się, że korzystanie z interfejsu jest po prostu trochę "za dużo".

Pytanie A

W scenariuszu fragmenty załączam mają dość skupiony rolę, co oznacza, że ​​są wykonywane dla danej działalności i nie będą wykorzystywane w inny sposób, to jest koncepcyjnie źle ignorować realizacji interfejsu i po prostu zrób coś takiego, jak

((TestActivity) getActivity().myCustomMethod(); 

?

Dotyczy to również scenariusza, w którym (nie moja sprawa, ale po prostu potraktowanie go jako "w najgorszym"), moja działalność musi dotyczyć wielu różnych RÓŻNYCH fragmentów, co oznacza, że ​​powinna wdrożyć jedną metodę dla każdego. fragment powinien obsłużyć. To sprawia, że ​​kod staje się wielkim bałaganem "potencjalnie niepotrzebnych linii".

Idąc dalej: nadal za pomocą fragmentów "skupionych", których celem jest praca tylko w określony sposób, z wykorzystaniem zagnieżdżonych fragmentów?

Dodano je jak

public class TestFragment extends Fragment { 


    private void myTestMethod() { 

    NestedFragment nested = new NestedFragment(); 

    getChildFragmentManager() 
     .beginTransaction() 
     .add(R.id.container, nested) 
     .commit(); 
    } 

} 

ten wiąże NestedFragment do TestFragment. Powtarzam to raz, NestedFragment, podobnie jak TestFragment, ma być używany tylko w ten sposób, nie ma sensu pracować inaczej.

Wracając do pytania, jak mam się zachować w tej sytuacji?

Pytanie B

1) powinien zapewniać interfejs w NestedFragment i zrobić tak, że TestFragments realizuje NestedFragmentInterface? W tym przypadku chciałbym pełnić następujące

NestedFragment

public class NestedFragment extends Fragment { 

    private NestedFragmentInterface listener; 

    public interface NestedFragmentInterface { 

     void actionMethodNested(); 

    } 


    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 

     if (getParentFragment() instanceof NestedFragmentInterface) { 
      listener = (NestedFragmentInterface) getParentFragment(); 
     } 

     // sending the event 
     if (listener != null) listener.actionMethodNested(); 
    } 

} 

2) powinien (lub może) ignoruję interfejs i zadzwoń

getParentFragment().publicParentMethod(); 

?

3) należy utworzyć interfejs w NestedFragment, ale niech aktywnośćrealizuje go, tak że aktywnośćwezwie TestFragment?

Pytanie C

odniesieniu do koncepcji z wykorzystaniem aktywności jako pomostu pomiędzy fragmentami wierzę, to jest tak, dla prawidłowego cyklu obsługi wszystkich tych obiektów. Czy nadal jest możliwe wykonanie bezpośredniego fragmentu od fragmentu (za pomocą interfejsu lub bezpośrednie wywoływanie metod publicznych) podczas próby ręcznego obsługiwania wyjątku, który system może mi wyrzucić?

+0

Sprawdź, czy to pomaga: https://corner.squareup.com/2014/10/advocating-against-android-fragments.html –

+0

Przeczytałem opublikowany przez Ciebie link i chociaż był to rzeczywiście interesujący artykuł z Wiele informacji, obawiam się, że po prostu nie odpowiada na moje pytania. I tak dziękuję – FrancescoC

Odpowiedz

4

Spróbuję to wszystko oczyścić.

Po pierwsze, rozważ podejście do ustawiania detektora dla fragmentu.Niedopuszczalne jest ustawienie detektora w metodzie onViewCreated, ponieważ powoduje on nadmiar detektora resetu, który jest tworzony. Wystarczy ustawić go na metodę onAttach.

Powiedziałem o liniach kodu. Weź mnie do zauważenia, dobrze jest, aby BaseFragment zaimplementował typowe zachowanie w twojej aplikacji jako ustawienie FragmentListener tworzącego widok z zasobu.

Co więcej, aby zmniejszyć linie kodu i uzyskać część ponownego wykorzystania kodu, można użyć generycznych w BaseFragment. Więc spójrz na następny fragment kodu:

public abstract BaseFragment<T extends BaseFragmentListener> extends Fragment { 

    T mListener; 

    public void onAttach(Activity activity) { 
    super.onAttach(activity); 
    if (Activity instanceof T) 
     mListener = (T) activity; 
    } 

    abstract int getLayoutResourceId(); 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     View layout = inflater.inflate(getLayoutResourceId(), null); 
     // you can use some view injected tools here, mb ButterKnife 
     return layout; 
    } 
} 

Odpowiedź A (dla zapytania A):

Jeśli masz fragment tylko dokładnie jedno działanie trzeba podjąć decyzję: „Czy naprawdę trzeba użyć Fragment tutaj?” . Ale dobrze jest mieć fragment dokładnie dla jednej czynności, aby wyodrębnić logikę widoku z działania i oczyścić logikę podstawową. Ale aby usunąć logikę architektury podstawowej dla aplikacji, użyj opcji Słuchacze. Ułatwi to życie innym programistom.

Odpowiedź B: W przypadku zagnieżdżonych fragmentów musisz rozwiązać, co trzeba, aby użyć dokładnej aktywności lub po prostu fragmentów i użyć go jako pomostu do innego systemu. Jeśli wiesz, że zagnieżdżony fragment będzie zagnieżdżony za każdym razem, musisz zadeklarować fragment macierzysty jako detektor, w przeciwnym razie musisz zastosować inne podejście.

Uwaga: Jako podstawowe podejście do komunikacji między różnymi częściami aplikacji możesz używać zdarzeń, spróbuj na przykład spojrzeć na magistralę zdarzeń. Daje ci to wspólne podejście do komunikacji i możesz wyodrębnić logikę wywoływania niestandardowych metod słuchaczy, a więcej, cała logika będzie umiejscowiona w wydarzeniach związanych z obsługą, a będziesz miał jeden system mediatora do współpracy.

Odpowiedź C: Częściowo wyjaśniam jedno z podejść do współpracy między fragmentami. Korzystanie z jednego dispatchera zdarzeń pozwala uniknąć wielu słuchaczy dla wszystkich różnych komunikacji. Czasami jest to bardzo opłacalne.

Lub myślę, że jest bardziej użyteczne używanie Aktywności lub innych żyć w Klasie w Działaniu, jako mediatora do współpracy Fragmentów, ponieważ istnieje wiele sytuacji, w których Fragmenty zmieniają się w trakcie cyklu życia zarówno podczas obsługi, jak i systemu. I skupia całą tę logikę w jednym miejscu i czyni twój kod bardziej klarownym.

Mam nadzieję, że moje rozważania ci pomogą.

+0

Dziękuję, to była świetna odpowiedź, wyszczególniona w logice i pomocna, dała mi kilka dobrych pomysłów:) – FrancescoC

10

zrobię mój najlepszy odpowiedzieć na ścianę tekstu tutaj :)

Pytanie A:

Fragmenty są przeznaczone do wielokrotnego użytku, które mogą być moduły plug and rozgrywanych z jakiejkolwiek aktywności. Z tego powodu jedyną poprawną drogą do połączenia z działaniem jest dziedziczenie aktywności z interfejsu zrozumiałego dla fragmentu.

public class MapFragment extends Fragment { 

    private MapFragmentInterface listener; 

    public interface MapFragmentInterface { 

     //All methods to interface with an activity 

    } 


    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     // sending the event 
     if (listener != null) listener.anyMethodInTheAboveInterface(); 
    } 

} 

wtedy aktywność implementować interfejs

public class MainActivity extends Activity implement MapFragmentInterface{ 

//All methods need to be implemented here 
} 

Daje to fragment być używany z dowolnym aktywności dopóki aktywność implementuje ten interfejs. Powodem, dla którego potrzebujesz tego interfejsu, jest to, że fragment może być używany z dowolną aktywnością. Wywołanie metody takiej jak

((TestActivity) getActivity().myCustomMethod(); 

polega na tym, że Twój fragment może działać tylko w ramach działania testowego i dlatego "łamie" reguły fragmentów.

Pytanie B i C:

Zakładając, że jesteś po odpowiednie wytyczne dla fragmentów i że są one niezależne moduły. Wtedy nigdy nie powinieneś mieć sytuacji, w której fragmenty muszą się od siebie nawzajem wiedzieć. 99% czasu, w którym ludzie myślą, że potrzebują fragmentów do bezpośredniej komunikacji, mogą ponownie zrekompensować swój problem sytuacji, którą dałem powyżej, używając znaku MVC lub czegoś podobnego. Aktywność działa jak kontroler i informuje fragmenty o konieczności aktualizacji, a następnie tworzy osobny magazyn danych.

+0

Następnie, z tego co piszesz, rozumiem, że to co robię jest możliwe, ale nie sugeruję, ponieważ użycie jest poza pierwotnym zakresem. To nie jest coś szkodliwego, ale po prostu nie jest używane tak, jak pierwotnie zamierzano. Jak bardzo się mylę? :) – FrancescoC

+0

Twoje 100% poprawne. Podobnie jak w przypadku wszystkich programów, istnieje wiele sposobów robienia rzeczy. Dużo czasu zrobię nawet dokładnie tak, jak to opisałeś, bo wiem, że mój fragment będzie używany tylko w tej jednej czynności. Jednak jeśli próbujesz być "poprawny", powinieneś zrobić to za pomocą interfejsu, aby jak najlepiej oddzielić swoją reklamę kodu. Jeśli masz czas i pieniądze, zawsze powinieneś zawsze budować swoją aplikację w odpowiedni sposób :) – nbroeking

+0

Nagroda Bounty:) – FrancescoC