Porównaj ceny domen i usług IT, sprzedawców z całego świata

ViewPager i fragmenty - jaki jest właściwy sposób na zapisanie stanu fragmentu?


Fragmenty wydają się bardzo dobre do dzielenia logiki interfejsu użytkownika na niektóre moduły. Ale wraz z
ViewPager
jego cykl życia jest dla mnie nadal niejasny. Zatem myśli guru są niezbędne!

Edytować
>
Zobacz głupie rozwiązanie poniżej ;-)

Skala
>
Główne działanie zawiera
ViewPager
z fragmentami. Te fragmenty mogą implementować nieco inną logikę dla innych (nadpisanych) akcji, więc dane fragmentu są wypełniane przez interfejs wywołania zwrotnego wewnątrz akcji. I wszystko działa dobrze przy pierwszym uruchomieniu, ale! ....

Problem
>
Kiedy akcja jest odtwarzana (na przykład, gdy zmienia się orientacja), to samo dzieje się z fragmentami
ViewPager
. Kod (znajdziesz poniżej) mówi, że za każdym razem, gdy tworzone jest działanie, próbuję utworzyć nowy adapter
ViewPager
Fragment, taki sam jak Fragments (może to jest problem), ale FragmentManager już gdzieś przechowuje te wszystkie fragmenty (gdzie?) i uruchamia dla nich silnik odtwarzania. Tak więc silnik odtwarzania wywołuje "stare" fragmenty onAttach, onCreateView, itp. Używając mojego interfejsu wywołania zwrotnego, wywołaj inicjalizację danych za pomocą zaimplementowanej metody akcji. Ale ta metoda wskazuje na nowo utworzony fragment, który jest tworzony za pomocą metody onCreate działania.

Pytanie
>
Może używam złych szablonów, ale nawet książka o Androidzie 3 Pro niewiele o tym mówi. W związku z tym ,

Zapraszamy
, daj mi jedno lub dwa i pokaż mi, jak to zrobić dobrze. Wielkie dzięki!

Kod
>Podstawowa działalność

public class DashboardActivity extends BasePagerActivity implements OnMessageListActionListener {private MessagesFragment mMessagesFragment;@Override
protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState); setContentView(R.layout.viewpager_container);
new DefaultToolbar(this);// create fragments to use
mMessagesFragment = new MessagesFragment();
mStreamsFragment = new StreamsFragment();// set titles and fragments for view pager
Map<String, Fragment> screens = new LinkedHashMap<String, Fragment>();
screens.put(getApplicationContext().getString(R.string.dashboard_title_dumb), new DumbFragment());
screens.put(getApplicationContext().getString(R.string.dashboard_title_messages), mMessagesFragment);// instantiate view pager via adapter
mPager = (ViewPager) findViewById(R.id.viewpager_pager);
mPagerAdapter = new BasePagerAdapter(screens, getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);// set title indicator
TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.viewpager_titles);
indicator.setViewPager(mPager, 1);}/* set of fragments callback interface implementations */@Override
public void onMessageInitialisation() { Logger.d("Dash onMessageInitialisation");
if (mMessagesFragment != null)
mMessagesFragment.loadLastMessages();
}@Override
public void onMessageSelected(Message selectedMessage) { Intent intent = new Intent(this, StreamActivity.class);
intent.putExtra(Message.class.getName(), selectedMessage);
startActivity(intent);
}
Pomocnik BasePagerActivity aka

public class BasePagerActivity extends FragmentActivity {BasePagerAdapter mPagerAdapter;
ViewPager mPager;
}
Adapter

public class BasePagerAdapter extends FragmentPagerAdapter implements TitleProvider {private Map<String, Fragment> mScreens;public BasePagerAdapter(Map<String, Fragment> screenMap, FragmentManager fm) { super(fm);
this.mScreens = screenMap;
}@Override
public Fragment getItem(int position) { return mScreens.values().toArray(new Fragment[mScreens.size()])[position];
}@Override
public int getCount() { return mScreens.size();
}@Override
public String getTitle(int position) { return mScreens.keySet().toArray(new String[mScreens.size()])[position];
}// hack. we don't want to destroy our fragments and re-initiate them after
@Override
public void destroyItem(View container, int position, Object object) {// TODO Auto-generated method stub
}}
Fragment

public class MessagesFragment extends ListFragment {private boolean mIsLastMessages;private List<Message> mMessagesList;
private MessageArrayAdapter mAdapter;private LoadMessagesTask mLoadMessagesTask;
private OnMessageListActionListener mListener;// define callback interface
public interface OnMessageListActionListener {
public void onMessageInitialisation();
public void onMessageSelected(Message selectedMessage);
}@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// setting callback
mListener = (OnMessageListActionListener) activity;
mIsLastMessages = activity instanceof DashboardActivity;}@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
inflater.inflate(R.layout.fragment_listview, container);
mProgressView = inflater.inflate(R.layout.listrow_progress, null);
mEmptyView = inflater.inflate(R.layout.fragment_nodata, null);
return super.onCreateView(inflater, container, savedInstanceState);
}@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);// instantiate loading task
mLoadMessagesTask = new LoadMessagesTask();// instantiate list of messages
mMessagesList = new ArrayList<Message>();
mAdapter = new MessageArrayAdapter(getActivity(), mMessagesList);
setListAdapter(mAdapter);
}@Override
public void onResume() {
mListener.onMessageInitialisation();
super.onResume();
}public void onListItemClick(ListView l, View v, int position, long id) {
Message selectedMessage = (Message) getListAdapter().getItem(position);
mListener.onMessageSelected(selectedMessage);
super.onListItemClick(l, v, position, id);
}/* public methods to load messages from host acitivity, etc... */
}


Decyzja
>
Głupim rozwiązaniem jest przechowywanie fragmentów w onSaveInstanceState (aktywność hosta) za pomocą putFragment i umieszczanie ich wewnątrz onCreate przez getFragment. Ale nadal mam dziwne przeczucie, że to nie powinno działać w ten sposób ... Zobacz kod poniżej:
@Override
protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState);
getSupportFragmentManager()
.putFragment(outState, MessagesFragment.class.getName(), mMessagesFragment);
}protected void onCreate(Bundle savedInstanceState) {
Logger.d("Dash onCreate");
super.onCreate(savedInstanceState); ...
// create fragments to use
if (savedInstanceState != null) {
mMessagesFragment = (MessagesFragment) getSupportFragmentManager().getFragment( savedInstanceState, MessagesFragment.class.getName());
StreamsFragment.class.getName());
}
if (mMessagesFragment == null)
mMessagesFragment = new MessagesFragment();
...
}

Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Kiedy
FragmentPagerAdapter
dodaje fragment do FragmentManager, używa specjalnego tagu opartego na konkretnej pozycji, w której zostanie umieszczony fragment.
FragmentPagerAdapter.getItem (int position)
jest wywoływane tylko gdy fragment na to stanowisko nie istnieje. Po przestawieniu system Android zauważy, że już utworzył/zapisał fragment dla tej konkretnej pozycji, więc po prostu próbuje połączyć się z nim ponownie za pomocą
FragmentManager.findFragmentByTag ()
zamiast tworzyć nowy. Wszystko to dzieje się za darmo, gdy używasz metody
FragmentPagerAdapter
, dlatego zwykle kod inicjujący fragmentu znajduje się wewnątrz metody
getItem (int)
.
Nawet jeśli nie używaliśmy
FragmentPagerAdapter
, nie warto za każdym razem tworzyć nowego fragmentu w
Activity.onCreate (Bundle)
. Jak już zauważyłeś, po dodaniu fragmentu do FragmentManager zostanie on dla Ciebie odtworzony po obróceniu i nie ma potrzeby dodawania go ponownie. Jest to częsta przyczyna błędów podczas pracy z fragmentami.
Typowe podejście do pracy z fragmentami to:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); ... CustomFragment fragment;
if (savedInstanceState != null) {
fragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag("customtag");
} else {
fragment = new CustomFragment();
getSupportFragmentManager().beginTransaction().add(R.id.container, fragment, "customtag").commit();
} ...}

Korzystając z
FragmentPagerAdapter
, przenosimy kontrolę nad fragmentami na adapter i nie musimy wykonywać powyższych kroków. Domyślnie wstępnie ładuje tylko jeden fragment z przodu iz tyłu bieżącej pozycji (chociaż nie niszczy ich, chyba że użyjesz
FragmentStatePagerAdapter
). Jest to kontrolowane

ViewPager.setOffscreenPageLimit(int)
http://developer.android.com/r ... 29... Z tego powodu bezpośrednie wywołanie metod na fragmentach poza adapterem nie jest gwarantowane, ponieważ mogą one nawet nie istnieć.
Krótko mówiąc, twoja decyzja o użyciu
putFragment
, aby móc później pobrać link, nie jest tak szalona i nie różni się zbytnio od zwykłego sposobu używania fragmentów (powyżej). W przeciwnym razie trudno jest uzyskać link, ponieważ fragment jest dodawany przez adapter, a nie przez Ciebie osobiście. Po prostu upewnij się, że
offscreenPageLimit
jest wystarczająco wysoki, aby załadować żądane fragmenty w dowolnym momencie, ponieważ polegasz na jego obecności. Pomija to możliwości leniwego ładowania ViewPagera, ale wygląda na to, że właśnie tego chcesz dla swojej aplikacji.
Innym podejściem jest przesłonięcie
FragmentPageAdapter.instantiateItem (View, int)
i zachowanie odniesienia do fragmentu zwróconego z supercall przed zwróceniem go (ma logikę do znalezienia fragmentu, jeśli jest już obecny).
Aby uzyskać pełniejszy obraz, przyjrzyj się niektórym źródłom.

FragmentPagerAdapter
http://grepcode.com/file/repos ... v%3Df
(krótki i

ViewPager
http://grepcode.com/file/repos ... v%3Df
(długo).
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Chcę zaoferować rozwiązanie, które się rozszerza
świetna odpowiedź
https://stackoverflow.com/a/9646622/708906
antonyt
i wzmianka o zastępowaniu
FragmentPageAdapter.instantiateItem (View, int)
w celu zachowania linków do wygenerowanych
fragmentów
, aby można było nad nimi pracować później. Powinno to również działać z
FragmentStatePagerAdapter
; Szczegółowe informacje można znaleźć w uwagach.
Oto prosty przykład, jak uzyskać link
Fragments
zwracany przez
FragmentPagerAdapter
, który jest niezależny od wewnętrznego zestawu
tagów
w
Fragmenty
. Kluczem jest zastąpienie
instantiateItem()
http://grepcode.com/file/repos ... %2383

i zapisz tam linki,

i

nie w
getItem ()
.
public class SomeActivity extends Activity {
private FragmentA m1stFragment;
private FragmentB m2ndFragment;// other code in your Activity... private class CustomPagerAdapter extends FragmentPagerAdapter {
// other code in your custom FragmentPagerAdapter... public CustomPagerAdapter(FragmentManager fm) {
super(fm);
} @Override
public Fragment getItem(int position) {
// Do NOT try to save references to the Fragments in getItem(),
// because getItem() is not always called. If the Fragment
// was already created then it will be retrieved from the FragmentManger
// and not here (i.e. getItem() won't be called again).
switch (position) {
case 0:
return new FragmentA();
case 1:
return new FragmentB();
default:
// This should never happen. Always account for each position above
return null;
}
}// Here we can finally safely save a reference to the created
// Fragment, no matter where it came from (either getItem() or
// FragmentManger). Simply save the returned Fragment from
// super.instantiateItem() into an appropriate reference depending
// on the ViewPager position.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// save the appropriate reference depending on position
switch (position) {
case 0:
m1stFragment = (FragmentA) createdFragment;
break;
case 1:
m2ndFragment = (FragmentB) createdFragment;
break;
}
return createdFragment;
}
} public void someMethod() {
// do work on the referenced Fragments, but first check if they
// even exist yet, otherwise you'll get an NPE. if (m1stFragment != null) {
// m1stFragment.doWork();
} if (m2ndFragment != null) {
// m2ndFragment.doSomeWorkToo();
}
}
}


lub

jeśli wolisz pracować z
tagami
zamiast ze zmiennymi składowymi klasy/odwołaniami do
fragmentów
, możesz również pobrać
tagi
ustawione przez
FragmentPagerAdapter
w ten sam sposób:
UWAGA: nie dotyczy to
FragmentStatePagerAdapter
, ponieważ nie ustawia
tagów
podczas tworzenia swoich
fragmentów
.
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
// get the tags set by FragmentPagerAdapter
switch (position) {
case 0:
String firstTag = createdFragment.getTag();
break;
case 1:
String secondTag = createdFragment.getTag();
break;
}
// ... save the tags somewhere so you can reference them later
return createdFragment;
}

Zauważ, że ta metoda nie polega na naśladowaniu wewnętrznego tagu
ustawionego przez
FragmentPagerAdapter
, ale zamiast tego używa odpowiednich interfejsów API do ich pobierania. Dzięki temu, nawet jeśli
tag
zmieni się w przyszłych wersjach
SupportLibrary
, nadal będziesz bezpieczny.

Nie zapomnij

że w zależności od projektu
Activity
Fragmenty
, nad którymi próbujesz pracować, mogą istnieć lub nie istnieć, więc powinieneś wziąć to pod uwagę, ustawiając
null
przed użyciem linków.

Co więcej, jeśli zamiast

Ponieważ pracujesz z
FragmentStatePagerAdapter
, nie chcesz przechowywać twardych linków do swoich
Fragmentów
, ponieważ możesz ich mieć dużo i twarde linki niepotrzebnie będą przechowywać je w pamięci . Zamiast tego zachowaj odwołania
Fragment
w zmiennych
WeakReference
zamiast domyślnych. Podobne do tego:
WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
// reference hasn't been cleared yet; do work...
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Znalazłem inne stosunkowo proste rozwiązanie twojego pytania.
Jak widać z

kod źródłowy FragmentPagerAdapter
http://grepcode.com/file/repos ... 28int,int%29, fragmenty sterowane przez
FragmentPagerAdapter
są przechowywane w
FragmentManager
pod tagiem wygenerowanym przez:
String tag="android:switcher:" + viewId + ":" + index;

viewId
to
container.getId ()
,
container
to Twoja instancja
ViewPager
.
index
to pozycja fragmentu. Dlatego możesz przechowywać identyfikator obiektu w
outState
: [/code]
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("viewpagerid" , mViewPager.getId() );
}@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
viewpagerid=savedInstanceState.getInt("viewpagerid", -1 ); MyFragmentPagerAdapter titleAdapter = new MyFragmentPagerAdapter (getSupportFragmentManager() , this);
mViewPager = (ViewPager) findViewById(R.id.pager);
if (viewpagerid != -1 ){
mViewPager.setId(viewpagerid);
}else{
viewpagerid=mViewPager.getId();
}
mViewPager.setAdapter(titleAdapter);

Jeśli chcesz utworzyć link do tego fragmentu, możesz pobrać if z
FragmentManager
, na przykład:
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewpagerid + ":0")
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Chcę zaproponować alternatywne rozwiązanie dla być może nieco innego przypadku, ponieważ wiele moich poszukiwań odpowiedzi nieustannie prowadziło mnie do tego tematu.

Mój przypadek

- Tworzę/dodaję strony dynamicznie i przenoszę je do ViewPager, ale po obróceniu (onConfigurationChange) otrzymuję nową stronę, ponieważ oczywiście OnCreate jest wywoływany ponownie. Ale chcę zachować łącze do wszystkich stron, które zostały utworzone przed rotacją.

Problem

- Nie mam unikalnych identyfikatorów dla każdego tworzonego przeze mnie fragmentu, więc jedynym sposobem na odniesienie było jakoś przechowywanie referencji w tablicy, która zostanie przywrócona po przestawieniu/skonfigurowaniu.

Objazd

koncepcja klucza ścieżki polegała na tym, że akcja (która renderuje fragmenty) zarządza również tablicą odwołań do istniejących fragmentów, ponieważ ta akcja może używać pakietów w onSaveInstanceState
public class MainActivity extends FragmentActivity

Dlatego w ramach tego działania deklaruję prywatnemu członkowi śledzenie otwartych stron
private List<Fragment> retainedPages = new ArrayList<Fragment>();

Jest to aktualizowane za każdym razem, gdy onSaveInstanceState jest wywoływany i przywracany w onCreate
@Override
protected void onSaveInstanceState(Bundle outState) {
retainedPages = _adapter.exportList();
outState.putSerializable("retainedPages", (Serializable) retainedPages);
super.onSaveInstanceState(outState);
}
.. więc po zapisaniu można go odzyskać ...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); if (savedInstanceState != null) {
retainedPages = (List<Fragment>) savedInstanceState.getSerializable("retainedPages");
}
_mViewPager = (CustomViewPager) findViewById(R.id.viewPager);
_adapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager());
if (retainedPages.size() > 0) {
_adapter.importList(retainedPages);
}
_mViewPager.setAdapter(_adapter);
_mViewPager.setCurrentItem(_adapter.getCount()-1);
}

Były to niezbędne zmiany w głównym działaniu, więc potrzebowałem członków i metod w moim FragmentPagerAdapter, aby to działało, więc wewnątrz
public class ViewPagerAdapter extends FragmentPagerAdapter

identyczna konstrukcja (jak pokazano powyżej w MainActivity)
private List<Fragment> _pages = new ArrayList<Fragment>();

i ta synchronizacja (jak opisano powyżej w onSaveInstanceState) jest obsługiwana właśnie przez te metody
public List<Fragment> exportList() {
return _pages;
}public void importList(List<Fragment> savedPages) {
_pages = savedPages;
}

Wreszcie w klasie fragmentów
public class CustomFragment extends Fragment

były dwie zmiany, aby to zadziałało, po pierwsze
public class CustomFragment extends Fragment implements Serializable

a następnie dodaj to do onCreate, aby fragmenty nie zostały zniszczone
setRetainInstance(true);

Nadal jestem w trakcie owijania głowy wokół fragmentów i cyklu życia Androida, więc zastrzeżenie jest takie, że w tej metodzie mogą występować nadmiarowości/nieefektywności. Ale to działa dla mnie i mam nadzieję, że może być pomocne dla innych osób z podobnymi przypadkami.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Moje rozwiązanie jest bardzo prymitywne, ale działa: ponieważ moje fragmenty są generowane dynamicznie z zapisanych danych, po prostu usuwam wszystkie fragmenty z
PageAdapter
przed wywołaniem
super.onSaveInstanceState ()
i następnie utwórz je ponownie podczas tworzenia działania:
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt("viewpagerpos", mViewPager.getCurrentItem() );
mSectionsPagerAdapter.removeAllfragments();
super.onSaveInstanceState(outState);
}

Nie możesz ich usunąć w
onDestroy ()
, w przeciwnym razie otrzymasz ten wyjątek:
java.lang.IllegalStateException:
Can not perform this action after
onSaveInstanceState
Oto kod w adapterze strony:
public void removeAllfragments()
{
if ( mFragmentList != null ) {
for ( Fragment fragment : mFragmentList ) {
mFm.beginTransaction().remove(fragment).commit();
}
mFragmentList.clear();
notifyDataSetChanged();
}
}

Zapisuję bieżącą stronę i przywracam ją w
onCreate ()
po utworzeniu fragmentów.
if (savedInstanceState != null)
mViewPager.setCurrentItem( savedInstanceState.getInt("viewpagerpos", 0 ) );
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Co to jest
BasePagerAdapter
? Należy użyć jednego ze standardowych adapterów pagera -
FragmentPagerAdapter
lub
FragmentStatePagerAdapter
, w zależności od tego, czy chcesz fragmentów, które nie są już potrzebne
ViewPager
, albo przechowywane obok siebie (jako pierwsze) lub zachowywane w stanie (jako drugie) i odtwarzane w razie potrzeby.
Przykładowy kod do korzystania z
ViewPager
można znaleźć

tutaj
http://developer.android.com/t ... mples
Prawdą jest, że zarządzanie fragmentami w pagerze widoków między instancjami działań jest nieco skomplikowane, ponieważ
FragmentManager
we frameworku dba o zapisanie stanu i przywrócenie wszystkich aktywnych fragmentów utworzonych przez pager. Wszystko to naprawdę oznacza, że ​​po zainicjowaniu adapter musi upewnić się, że łączy się ponownie z odzyskanymi fragmentami. Możesz spojrzeć na kod
FragmentPagerAdapter
lub
FragmentStatePagerAdapter
, aby zobaczyć, jak to się robi.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli ktoś ma problem z tym, że jego FragmentStatePagerAdapter nie przywraca poprawnie stanu jego fragmentów ... tj ... nowych fragmentów, są one tworzone przez FragmentStatePagerAdapter zamiast przywracania ich ze stanu ...
Upewnij się, że wywołałeś
ViewPager.setOffscreenPageLimit ()
PRZED wywołaniem
ViewPager.setAdapter (fragmentStatePagerAdapter)
Wywołując
ViewPager.setOffscreenPageLimit ()
... ViewPager

natychmiast

spojrzy na jego adapter i spróbuje zdobyć jego fragmenty. Może się to zdarzyć, zanim ViewPager będzie miał szansę przywrócić fragmenty z saveInstanceState (tworząc w ten sposób nowe fragmenty, których nie można ponownie zainicjować z SavedInstanceState, ponieważ są nowe).
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Wymyśliłem to proste i eleganckie rozwiązanie. Zakłada, że ​​aktywność jest odpowiedzialna za tworzenie fragmentów, a adapter po prostu je obsługuje.
To jest kod adaptera (nic dziwnego, poza tym, że
mFragments
to lista fragmentów obsługiwanych przez działanie)
class MyFragmentPagerAdapter extends FragmentStatePagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
} @Override
public Fragment getItem(int position) {
return mFragments.get(position);
} @Override
public int getCount() {
return mFragments.size();
} @Override
public int getItemPosition(Object object) {
return POSITION_NONE;
} @Override
public CharSequence getPageTitle(int position) {
TabFragment fragment = (TabFragment)mFragments.get(position);
return fragment.getTitle();
}
}

Cały problem z tym wątkiem polega na uzyskaniu odniesienia do „starych” fragmentów, więc używam tego kodu w działaniu onCreate.
if (savedInstanceState!=null) {
if (getSupportFragmentManager().getFragments()!=null) {
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
mFragments.add(fragment);
}
}
}

Oczywiście w razie potrzeby możesz dodatkowo dostosować ten kod, na przykład upewniając się, że fragmenty są instancjami określonej klasy.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Aby uzyskać fragmenty po zmianie orientacji, musisz użyć .getTag ().
getSupportFragmentManager().findFragmentByTag("android:switcher:" + viewPagerId + ":" + positionOfItemInViewPager)

Aby uzyskać trochę więcej przetwarzania, napisałem własną ArrayList dla mojego PageAdapter, aby uzyskać fragment przez viewPagerId i FragmentClass w dowolnej pozycji:
public class MyPageAdapter extends FragmentPagerAdapter implements Serializable {
private final String logTAG = MyPageAdapter.class.getName() + ".";private ArrayList<MyPageBuilder> fragmentPages;public MyPageAdapter(FragmentManager fm, ArrayList<MyPageBuilder> fragments) {
super(fm);
fragmentPages = fragments;
}@Override
public Fragment getItem(int position) {
return this.fragmentPages.get(position).getFragment();
}@Override
public CharSequence getPageTitle(int position) {
return this.fragmentPages.get(position).getPageTitle();
}@Override
public int getCount() {
return this.fragmentPages.size();
}
public int getItemPosition(Object object) {
//benötigt, damit bei notifyDataSetChanged alle Fragemnts refrehsed werden Log.d(logTAG, object.getClass().getName());
return POSITION_NONE;
}public Fragment getFragment(int position) {
return getItem(position);
}public String getTag(int position, int viewPagerId) {
//getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.shares_detail_activity_viewpager + ":" + myViewPager.getCurrentItem()) return "android:switcher:" + viewPagerId + ":" + position;
}public MyPageBuilder getPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
return new MyPageBuilder(pageTitle, icon, selectedIcon, frag);
}
public static class MyPageBuilder { private Fragment fragment; public Fragment getFragment() {
return fragment;
} public void setFragment(Fragment fragment) {
this.fragment = fragment;
} private String pageTitle; public String getPageTitle() {
return pageTitle;
} public void setPageTitle(String pageTitle) {
this.pageTitle = pageTitle;
} private int icon; public int getIconUnselected() {
return icon;
} public void setIconUnselected(int iconUnselected) {
this.icon = iconUnselected;
} private int iconSelected; public int getIconSelected() {
return iconSelected;
} public void setIconSelected(int iconSelected) {
this.iconSelected = iconSelected;
} public MyPageBuilder(String pageTitle, int icon, int selectedIcon, Fragment frag) {
this.pageTitle = pageTitle;
this.icon = icon;
this.iconSelected = selectedIcon;
this.fragment = frag;
}
}public static class MyPageArrayList extends ArrayList<MyPageBuilder> {
private final String logTAG = MyPageArrayList.class.getName() + "."; public MyPageBuilder get(Class cls) {
// Fragment über FragmentClass holen
for (MyPageBuilder item : this) {
if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
return super.get(indexOf(item));
}
}
return null;
} public String getTag(int viewPagerId, Class cls) {
// Tag des Fragment unabhängig vom State z.B. nach bei Orientation change
for (MyPageBuilder item : this) {
if (item.fragment.getClass().getName().equalsIgnoreCase(cls.getName())) {
return "android:switcher:" + viewPagerId + ":" + indexOf(item);
}
}
return null;
}
}

Po prostu utwórz MyPageArrayList z fragmentami:
myFragPages = new MyPageAdapter.MyPageArrayList(); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_data_frag),
R.drawable.ic_sd_storage_24dp,
R.drawable.ic_sd_storage_selected_24dp,
new WidgetDataFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_color_frag),
R.drawable.ic_color_24dp,
R.drawable.ic_color_selected_24dp,
new WidgetColorFrag())); myFragPages.add(new MyPageAdapter.MyPageBuilder( getString(R.string.widget_config_textsize_frag),
R.drawable.ic_settings_widget_24dp,
R.drawable.ic_settings_selected_24dp,
new WidgetTextSizeFrag()));

i dodaj je do viewPager:
mAdapter = new MyPageAdapter(getSupportFragmentManager(), myFragPages);
myViewPager.setAdapter(mAdapter);

po tym można uzyskać po orientacji zmienić właściwy fragment używając jego klasy:
WidgetDataFrag dataFragment = (WidgetDataFrag) getSupportFragmentManager()
.findFragmentByTag(myFragPages.getTag(myViewPager.getId(), WidgetDataFrag.class));
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Dodaj:
@SuppressLint("ValidFragment")

przed twoimi zajęciami.
nie działa coś takiego:
@SuppressLint({ "ValidFragment", "HandlerLeak" })

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się