26

Mam aplikację, która zajmuje się fragmentami i ViewPager. Mam trzy fragmenty w ViewPager. Gdy przełączasz się między nimi, powoduje to, że pozostałe dwa fragmenty wywołują swoje metody onCreateView. Jak zrobić to tylko raz, tylko gdy tworzony jest program FragmentActivity ??? Przeczytałem kilka pytań i wypróbowałem rozwiązania, ale fragmenty nadal zachowują się tak samo.Dlaczego fragment onCreateView fragmentu, onCreate, onActivityCreated nazywa się

ListFragment onCreate called twice
onCreate() and onCreateView() invokes a lot more than required (Fragments)

Oto niektóre kodu, jeśli pomaga wam, chłopaki:

główną działalność:

public class StartingActivity extends FragmentActivity implements View.OnClickListener { 
ViewPager viewPager; 
    CirclePageIndicator pageIndicator; 

    Button discount; 
    Button qrCode; 
    Button pay; 
    TabHost tabHost; 

    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.starting_layout); 
     viewPager = (ViewPager) findViewById(R.id.pager); 

     if (savedInstanceState == null) { 

      Fragment firstPage = Fragment.instantiate(this, FindTovarFragment.class.getName()); 
      Fragment secondPage = Fragment.instantiate(this, MainWindowActivity.class.getName()); 
      Fragment thirdPage = Fragment.instantiate(this, MapActivity.class.getName()); 

      if ((firstPage != null && !firstPage.isDetached())|| (secondPage != null && !secondPage.isDetached()) || (thirdPage != null && !thirdPage.isDetached())) { 

      List<Fragment> viewPagerFragments = new ArrayList<Fragment>(); 
      viewPagerFragments.add(firstPage); 
      viewPagerFragments.add(secondPage); 
      viewPagerFragments.add(thirdPage); 


      PageAdapter pageAdapter = new PageAdapter(getSupportFragmentManager(), viewPagerFragments); 

      viewPager.setAdapter(pageAdapter); 

      pageIndicator = (CirclePageIndicator) findViewById(R.id.circle); 
      pageIndicator.setViewPager(viewPager); 
      pageIndicator.setCurrentItem(pageAdapter.getCount() - 2); 
      } 
     } 

} 

MapActivity:

public class MapActivity extends Fragment implements OnMyLocationListener { 

    //Тэг для логов 
    private static final String TAG = "MapActivity"; 
    List<Address> addressList; 
    private static final String STRING_LOCATION = ""; 

    ArrayList<TorgCentr> randomTorgCentr; 
    ArrayList<String> torgCentrNames; 

    Context context; 
    AutoCompleteTextView searchTorgCentr; 
    OverlayManager overlayManager; 
    MapController mapController; 
    TextView textView; 
    double longitude; 
    double latitude; 
    double itemLongitude; 
    double itemLatitude; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     Log.d(TAG, "MapActivity onCreateView"); 


     View view = (LinearLayout) inflater.inflate(R.layout.map_layout, container, false); 
     final MapView mapView = (MapView) view.findViewById(R.id.map); 
     textView = (TextView) view.findViewById(R.id.searchlocation); 
     searchTorgCentr = (AutoCompleteTextView) view.findViewById(R.id.autoCompleteTextView); 

     mapView.showBuiltInScreenButtons(true); 
     mapController = mapView.getMapController(); 
     context = getActivity(); 
     return view; 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Log.d(TAG, "MapActivity onCreate"); 

    } 

    public void onActivityCreated(Bundle savedInstanceState) { 
     Log.d(TAG, "MapActivity onActivityCreated"); 
     context = getActivity(); 

     SetRightMapDisplayAddress rightMapDisplayAddress = new SetRightMapDisplayAddress(); 
     rightMapDisplayAddress.execute(STRING_LOCATION); 

     DownloadSuperMarketsArray superMarketsArray = new DownloadSuperMarketsArray(); 
     superMarketsArray.execute(); 

     overlayManager = mapController.getOverlayManager(); 
     overlayManager.getMyLocation().setEnabled(false); 

     super.onActivityCreated(savedInstanceState); 
    } 

drugie Frag ment:

public class MainWindowActivity extends Fragment { 

    private static final String TAG = "MainWindowActivity"; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     Log.d(TAG, "MainWindowActivity onCreateView"); 
     View view = (RelativeLayout) inflater.inflate(R.layout.main_window_layout, container, false); 
     if (container == null) { 
      return null; 
     } 
     return view; 
    } 
} 

I trzeci:

public class FindTovarFragment extends Fragment { 

    private static final String TAG= "FindTovarFragment"; 

    Context context; 
    ArrayList<Category> categories; 
    Spinner categoryContainer; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     Log.d(TAG, "FindTovarFragment onCreateView"); 

     View view = (LinearLayout) inflater.inflate(R.layout.find_tovar_main_layout, container, false); 
     categoryContainer = (Spinner) view.findViewById(R.id.category); 

     return view; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     Log.d(TAG, "FindTovarFragment onActivityCreated"); 
     DownloadCategory downloadCategory = new DownloadCategory(); 
     downloadCategory.execute(); 
    } 

Logi do MapActivity:

06-20 11:06:37.709: DEBUG/MapActivity(1290): MapActivity onCreate 
06-20 11:06:37.709: DEBUG/MapActivity(1290): MapActivity onCreateView 
06-20 11:06:38.509: DEBUG/MapActivity(1290): MapActivity onActivityCreated 

potem znowu i znowu:

06-20 11:07:53.239: DEBUG/MapActivity(1290): MapActivity onCreate 
06-20 11:07:53.239: DEBUG/MapActivity(1290): MapActivity onCreateView 
06-20 11:07:53.429: DEBUG/MapActivity(1290): MapActivity onActivityCreated 
06-20 11:08:23.029: DEBUG/MapActivity(1290): MapActivity onCreate 
06-20 11:08:23.039: DEBUG/MapActivity(1290): MapActivity onCreateView 
06-20 11:08:23.269: DEBUG/MapActivity(1290): MapActivity onActivityCreated 

Dziękuję bardzo z góry .

Odpowiedz

12

chciałbym zmienić architekturę w tym jeden na dokumentacji dla programistów Android:

http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html

ale chciałbym zmienić kilka rzeczy ...

1-chciałbym zmienić tą metodą:

/** 
    * The Fragment's UI is just a simple text view showing its 
    * instance number. 
    */ 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View v = inflater.inflate(R.layout.fragment_pager_list, container, false); 
     View tv = v.findViewById(R.id.text); 
     ((TextView)tv).setText("Fragment #" + mNum); 
     return v; 
    } 

Po coś takiego decydujemy, który fragment zapełnisz w zależności od pozycji podglądu:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { 
super.onCreateView(inflater, container, savedInstanceState); 

SupportFragmentManager ft = getChildFragmentManager().beginTransaction(); 

String tag = ""; 
Fragment fragment = null; 

    switch (mNum) { 
    case 0: 
    fragment = new MyFragmentZero(); 
    tag = FragmentTags.TAG_0; 
    break; 
    case 1: 
    fragment = new MyFragmentOne(); 
    tag = FragmentTags.TAG_3; 
    break; 
    case 2: 
    fragment = new MyFragmentTwo(); 
    tag = FragmentTags.TAG_2; 
    break; 
    default: 
    break; 
    } 

/*OPTIONAL We can pass arguments to the fragments 
Bundle args = new Bundle(); 
args.putInt(Arguments.ARG_POSITION, mNum); 
fragment.setArguments(args);*/ 

//Place the fragment in the container 
ft.replace(R.id.fragment_container fragment, tag); 
ft.commit(); 

//You need a base layout for all fragment and use nested fragments later or you can define the layout for each position(mNum) inside the switch. 
return inflater.inflate(R.layout.fragment_layout_default_for_all_views, container, 
    false); 
} 

W ten sposób będziesz miał dobrą architekturę i kiedy to działa, powinno być w porządku.

W każdym razie musisz wiedzieć, w jaki sposób viewPager obsługuje wypełnianie fragmentu w różnych pozycjach.

Po uruchomieniu na pozycji 0 tworzony jest fragment na pozycji 0 i pozycji 1.

Następnie po przesunięciu do pozycji 1 tworzony jest fragment na 2 pozycji, więc masz teraz trzy fragmenty utworzone w różnych pozycjach (0,1,2, zakładając, że masz tylko 3 strony w widoku ViewPager).

Przesuwamy się na pozycję 2, ostatni, a fragment na pierwszej pozycji (0) zostaje zniszczony, więc mamy teraz fragmenty na pozycjach 2 i 3.

Mam nadzieję, że pomogło i daj mi znać, jeśli masz jakiś problem. Na zdrowie

+0

Dziękuję za odpowiedź. Ale to jest dokładnie to, co zrobiłem. Problem polega na tym, że moja aplikacja pobiera wiele informacji, gdy fragmenty są tworzone i korzysta z geolokalizacji. Kiedy jeden fragment zostanie utworzony, a drugi zostanie zniszczony przez przeglądarkę, musi ponownie pobrać wszystko, a aplikacja szybko się zawiesi. Więc nie można dostosować widoku, aby nie niszczył obiektów? – PAcan

+0

Również nie myślę, aby nie niszczyć fragmentów, to dobry pomysł, to naprawdę złe podejście. Powinieneś zająć się zarządzaniem pamięcią i nie robić tego ... – jpardogo

+3

Proszę nie pobierać wszystkiego ponownie! Przechowuj te informacje na swojej aktywności (pobierasz wszystko, co potrzebne do swojej działalności tylko raz) i komunikujesz się z nią za pośrednictwem interfejsów tworząc fragment. Zmieniaj sposób wczytywania fragmentów, nie twórz listy fragmentów ani niczego w tym stylu, tylko wywołaj newInstance z adaptera. Przeczytaj uważnie dokumentację programisty Androida i postępuj zgodnie z tym kodem, myślę, że jest to najlepszy pomysł. Zmień nazwę MainWindowActivity, MapActivity na MainWindowFragment, MapFragment również będzie bardziej przejrzysty. – jpardogo

11

W końcu udało mi się to rozgryźć. Wystarczy zastąpić metodę destroyItem, aby nie niszczyła obiektów. Mam nadzieję, że przyda się to komuś.

@Override 
public void destroyItem(ViewGroup container, int position, Object object) { 
    Log.d(TAG, "destroy!"); 
} 
+0

czy mógłbyś wyjaśnić to nieco bardziej szczegółowo? Jak wygląda twoja metoda niszczenia? – Simulant

+0

Edytowałem moją odpowiedź – PAcan

+1

Dzięki ~ praca w porządku – HenryChuang

12

ViewPager domyślnie zatrzymuje się w pamięci 1 stronę, po obu stronach bieżącej strony. Nie można więc odtworzyć tych stron podczas przesuwania 1 strony w lewo/w prawo od bieżącej strony. Ale po przesunięciu o więcej niż jedną stronę w lewo/w prawo, ponownie tworzyłby tę stronę, dlatego nazywa się OnCreateView(), OnCreate().

Jeśli aplikacja korzysta z kilku stron 3, można zwiększyć liczbę stron do zachowania przez wywołanie,

mViewPager.setOffscreenPageLimit(2); 

Opisane here

+1

To powinno być zaakceptowaną odpowiedzią –

Powiązane problemy