wsparcie FragmentPagerAdapter zawiera odniesienia do starych fragmentów

OSTATNIE INFORMACJE:

Zawęziłem swój problem do tego, że fragmentManager zachowuje instancje starych fragmentów, a mój viewpager nie jest zsynchronizowany z moim Fragmentmanagerem. Zobacz ten problem... http://code.google.com/p/android/issues/detail?id=19211#makechanges . Nadal nie mam pojęcia, jak to rozwiązać. Wszelkie sugestie...

Próbowałem debugować to przez długi czas i każda pomoc byłaby bardzo mile widziana. Używam FragmentPagerAdapter, który przyjmuje listę takich fragmentów:

List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Fragment1.class.getName())); 
...
new PagerAdapter(getSupportFragmentManager(), fragments);

Implementacja jest standardowa. Używam ActionBarSherlock i biblioteki obliczeniowej V4 dla fragmentów.

Mój problem polega na tym, że po opuszczeniu aplikacji i otwarciu kilku innych aplikacji i powrocie fragmenty tracą odniesienie do fragmentu (tj. getActivity() == null). Nie mogę zrozumieć, dlaczego tak się dzieje. Próbowałem ręcznie ustawić setRetainInstance(true);, ale to nie pomaga. Domyśliłem się, że tak się dzieje. kiedy mój FragmentActivity zostanie zniszczony, jednak nadal dzieje się tak, jeśli otworzę aplikację przed otrzymaniem wiadomości dziennika. Jakieś pomysły?

@Override
protected void onDestroy(){
    Log.w(TAG, "DESTROYDESTROYDESTROYDESTROYDESTROYDESTROYDESTROY");
    super.onDestroy();
}

Adapter:

public class PagerAdapter extends FragmentPagerAdapter {
    private List<Fragment> fragments;

    public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);

        this.fragments = fragments;

    }

    @Override
    public Fragment getItem(int position) {

        return this.fragments.get(position);

    }

    @Override
    public int getCount() {

        return this.fragments.size();

    }

}

Jeden z moich fragmentów rozebrany, ale skomentowałem wszystko, co jest rozebrane i nadal nie działa...

public class MyFragment extends Fragment implements MyFragmentInterface, OnScrollListener {
...

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    handler = new Handler();    
    setHasOptionsMenu(true);
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    Log.w(TAG,"ATTACHATTACHATTACHATTACHATTACH");
    context = activity;
    if(context== null){
        Log.e("IS NULL", "NULLNULLNULLNULLNULLNULLNULLNULLNULLNULLNULL");
    }else{
        Log.d("IS NOT NULL", "NOTNOTNOTNOTNOTNOTNOTNOT");
    }

}

@Override
public void onActivityCreated(Bundle savedState) {
    super.onActivityCreated(savedState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.my_fragment,container, false);

    return v;
}


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

private void callService(){
    // do not call another service is already running
    if(startLoad || !canSet) return;
    // set flag
    startLoad = true;
    canSet = false;
    // show the bottom spinner
    addFooter();
    Intent intent = new Intent(context, MyService.class);
    intent.putExtra(MyService.STATUS_RECEIVER, resultReceiver);
    context.startService(intent);
}

private ResultReceiver resultReceiver = new ResultReceiver(null) {
    @Override
    protected void onReceiveResult(int resultCode, final Bundle resultData) {
        boolean isSet = false;
        if(resultData!=null)
        if(resultData.containsKey(MyService.STATUS_FINISHED_GET)){
            if(resultData.getBoolean(MyService.STATUS_FINISHED_GET)){
                removeFooter();
                startLoad = false;
                isSet = true;
            }
        }

        switch(resultCode){
        case MyService.STATUS_FINISHED: 
            stopSpinning();
            break;
        case SyncService.STATUS_RUNNING:
            break;
        case SyncService.STATUS_ERROR:
            break;
        }
    }
};

public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    inflater.inflate(R.menu.activity, menu);
}

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

public void onScroll(AbsListView arg0, int firstVisible, int visibleCount, int totalCount) {
    boolean loadMore = /* maybe add a padding */
        firstVisible + visibleCount >= totalCount;

    boolean away = firstVisible+ visibleCount <= totalCount - visibleCount;

    if(away){
        // startLoad can now be set again
        canSet = true;
    }

    if(loadMore) 

}

public void onScrollStateChanged(AbsListView arg0, int state) {
    switch(state){
    case OnScrollListener.SCROLL_STATE_FLING: 
        adapter.setLoad(false); 
        lastState = OnScrollListener.SCROLL_STATE_FLING;
        break;
    case OnScrollListener.SCROLL_STATE_IDLE: 
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_IDLE;
        break;
    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
        adapter.setLoad(true);
        if(lastState == SCROLL_STATE_FLING){
            // load the images on screen
        }

        lastState = OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
        break;
    }
}

@Override
public void onDetach(){
    super.onDetach();
    if(this.adapter!=null)
        this.adapter.clearContext();

    Log.w(TAG, "DETACHEDDETACHEDDETACHEDDETACHEDDETACHEDDETACHED");
}

public void update(final int id, String name) {
    if(name!=null){
        getActivity().getSupportActionBar().setTitle(name);
    }

}

}

Metoda update jest wywoływana, gdy użytkownik wchodzi w interakcję z innym fragmentem i getActivity zwraca null. Oto metoda drugiego fragmentu dzwonię...

((MyFragment) pagerAdapter.getItem(1)).update(id, name);

Uważam, że gdy aplikacja zostanie zniszczona, a następnie utworzona ponownie zamiast uruchamiać aplikację aż do domyślnego fragmentu, aplikacja uruchamia się, a następnie viewpager przechodzi do ostatniej znanej strony. Wydaje się to dziwne, czy aplikacja nie powinna załadować się do domyślnego fragmentu?

Author: Maurycy, 2012-03-15

13 answers

Napotkasz problem, ponieważ tworzysz i przechowujesz odwołania do swoich fragmentów poza PagerAdapter.getItem i próbujesz używać tych odwołań niezależnie od Viewpagera. Jak mówi Seraph, masz gwarancje, że fragment został utworzony / dodany do Viewpagera w określonym czasie - należy to uznać za szczegóły implementacji. ViewPager robi leniwe ładowanie swoich stron; domyślnie ładuje tylko bieżącą stronę, a tę po lewej i racja.

Jeśli umieścisz aplikację w tle, fragmenty dodane do menedżera fragmentów zostaną automatycznie zapisane. Nawet jeśli aplikacja zostanie zabita, informacje te zostaną przywrócone po ponownym uruchomieniu aplikacji.

Teraz rozważ, że przeglądałeś kilka stron, fragmenty A, B i C. wiesz, że zostały one dodane do menedżera fragmentów. Ponieważ używasz FragmentPagerAdapter, a nie FragmentStatePagerAdapter, fragmenty te zostaną dodane (ale potencjalnie odłączone) podczas przewijania do inne strony.

Weź pod uwagę, że potem prześlesz swoją aplikację, a potem zostanie ona zabita. Kiedy wrócisz, Android będzie pamiętał, że w Menedżerze fragmentów A, B I C miałeś fragmenty A, B I C, więc odtworzy je dla Ciebie, a następnie je dodaje. jednak te, które są teraz dodawane do menedżera fragmentów, nie są tymi, które masz na liście fragmentów w swojej aktywności.

FragmentPagerAdapter nie będzie próbował wywołać getPosition jeśli już istnieje fragment dodane dla danej pozycji strony. W rzeczywistości, ponieważ fragment odtworzony przez Androida nigdy nie zostanie usunięty, nie masz nadziei na zastąpienie go wywołaniem getPosition. Uzyskanie uchwytu na to jest również dość trudne do uzyskania odniesienia do niego, ponieważ został dodany z tagiem, który jest nieznany. Jest to z założenia; nie jesteś zniechęcany do mieszania się z fragmentami, którymi zarządza Pager widoku. Powinieneś wykonywać wszystkie swoje działania w obrębie fragmentu, komunikując się z działaniem, i Prośba o przejście na konkretną stronę, jeśli to konieczne.

Wróćmy do problemu z brakującą aktywnością. Wywołanie pagerAdapter.getItem(1)).update(id, name) Po tym wszystkim zwróci ci fragment z listy, , który nie został jeszcze dodany do menedżera fragmentów, a więc nie będzie miał odniesienia do aktywności. Sugerowałbym, że twoja metoda aktualizacji powinna zmodyfikować jakąś współdzieloną strukturę danych( ewentualnie zarządzaną przez aktywność), a następnie po przejściu na konkretną stronę może się narysować na podstawie tych zaktualizowanych danych.
 120
Author: antonyt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-16 23:50:11

Znalazłem proste rozwiązanie, które zadziałało dla mnie.

Spraw, aby twój adapter fragment rozszerza FragmentStatePagerAdapter zamiast FragmentPagerAdapter i nadpisuje metodę onSave, aby zwróciła null

@Override
public Parcelable saveState()
{
    return null;
}

To uniemożliwia Androidowi odtworzenie fragmentu


Dzień później znalazłem inne, lepsze rozwiązanie.

Wywołaj setRetainInstance(true) dla wszystkich swoich fragmentów i zapisz odniesienia do nich gdzieś. Zrobiłem to w zmiennej statycznej w mojej aktywności, ponieważ jest zadeklarowana jako singleTask a fragmenty mogą pozostać takie same przez cały czas.

W ten sposób android nie odtwarza fragmentów, ale używa tych samych instancji.

 108
Author: mc.dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-11 21:04:09

Rozwiązałem ten problem, uzyskując dostęp do moich fragmentów bezpośrednio przez FragmentManager zamiast przez FragmentPagerAdapter w ten sposób. Najpierw muszę znaleźć znacznik fragmentu wygenerowanego automatycznie przez FragmentPagerAdapter...

private String getFragmentTag(int pos){
    return "android:switcher:"+R.id.viewpager+":"+pos;
}

Potem po prostu dostaję odniesienie do tego fragmentu i robię to, czego potrzebuję...

Fragment f = this.getSupportFragmentManager().findFragmentByTag(getFragmentTag(1));
((MyFragmentInterface) f).update(id, name);
viewPager.setCurrentItem(1, true);

Wewnątrz moich fragmentów ustawiam setRetainInstance(false); tak, że mogę ręcznie dodawać wartości do pakietu savedInstanceState.

@Override
public void onSaveInstanceState(Bundle outState) {
    if(this.my !=null)
        outState.putInt("myId", this.my.getId());

    super.onSaveInstanceState(outState);
}

A następnie w OnCreate i chwyć ten klucz i przywróć stan fragmentu w razie potrzeby. Łatwe rozwiązanie, które trudno było (przynajmniej dla mnie) rozgryźć.

 30
Author: Maurycy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-16 20:33:20

Sprawdzone rozwiązanie na całym świecie.

getSupportFragmentManager() utrzymuje odniesienie null kilka razy i View pager nie tworzy nowego, ponieważ znajduje odniesienie do tego samego fragmentu. Tak więc to użycie getChildFragmentManager() rozwiązuje problem w prosty sposób.

Nie rób tego:

new PagerAdapter(getSupportFragmentManager(), fragments);

Zrób to:

new PagerAdapter(getChildFragmentManager() , fragments);

 26
Author: Vinayak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-17 20:59:27

Nie próbuj wchodzić w interakcje między fragmentami w Viewpagerze. Nie możesz zagwarantować, że inny fragment dołączony lub nawet istnieje. Jeśli chcesz zmienić tytuł actionbar z fragmentu, możesz to zrobić ze swojej aktywności. Użyj standardowego wzorca interfejsu:

public interface UpdateCallback
{
    void update(String name);
}

public class MyActivity extends FragmentActivity implements UpdateCallback
{
    @Override
    public void update(String name)
    {
        getSupportActionBar().setTitle(name);
    }

}

public class MyFragment extends Fragment
{
    private UpdateCallback callback;

    @Override
    public void onAttach(SupportActivity activity)
    {
        super.onAttach(activity);
        callback = (UpdateCallback) activity;
    }

    @Override
    public void onDetach()
    {
        super.onDetach();
        callback = null;
    }

    public void updateActionbar(String name)
    {
        if(callback != null)
            callback.update(name);
    }
}
 7
Author: Seraph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-15 22:40:29

Możesz usunąć fragmenty, gdy zniszczysz viewpagera, w moim przypadku usunąłem je na onDestroyView() mojego fragmentu:

@Override
public void onDestroyView() {

    if (getChildFragmentManager().getFragments() != null) {
        for (Fragment fragment : getChildFragmentManager().getFragments()) {
            getChildFragmentManager().beginTransaction().remove(fragment).commitAllowingStateLoss();
        }
    }

    super.onDestroyView();
}
 5
Author: Raoni Novellino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-08 22:46:43

Po kilku godzinach szukania podobnego problemu myślę, że mam inne rozwiązanie. Ten przynajmniej mi zadziałał i muszę tylko zmienić kilka linijek.

To jest problem, który miałem, mam działanie z pagerem widoku, który używa FragmentStatePagerAdapter z dwoma fragmentami. Wszystko działa dobrze, dopóki nie wymuszę aktywności, aby została zniszczona (opcje dewelopera) lub obrócę ekran. Zachowuję odniesienie do dwóch fragmentów po ich utworzeniu wewnątrz metody getItem.

W tym momencie aktywność zostanie utworzona ponownie i wszystko działa dobrze w tym momencie, ale straciłem odniesienie do moich fragmetns jak getItem nie ' dostać wywołane ponownie.

Oto jak naprawiłem ten problem, wewnątrz FragmentStatePagerAdapter:

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object aux = super.instantiateItem(container, position);

        //Update the references to the Fragments we have on the view pager
        if(position==0){
            fragTabOne = (FragOffersList)aux;
        }
        else{
            fragTabTwo = (FragOffersList) aux;
        }

        return aux;
    }

Nie otrzymasz ponownie wywołania getItem, jeśli adapter ma już wewnętrzne odniesienie do niego, i nie powinieneś tego zmieniać. Zamiast tego możesz uzyskać fragment, który jest używany, patrząc na ten drugi metoda instantiateItem (), która zostanie wywołana dla każdego z Twoich fragmentów.

Mam nadzieję, że to komuś pomoże.
 4
Author: Lancelot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 16:36:57

Ponieważ FragmentManager zadba o przywrócenie Twoich fragmentów, gdy tylko zostanie wywołana metoda onResume (), mam fragment wywołujący aktywność i dodający się do listy. W moim przypadku zapisuję to wszystko w mojej implementacji PagerAdapter. Każdy fragment zna swoją pozycję, ponieważ jest dodawany do argumentów fragmentu podczas tworzenia. Teraz, gdy muszę manipulować fragmentem w określonym indeksie, wszystko, co muszę zrobić, to użyć listy z mojego adaptera.

The poniżej znajduje się przykład adaptera dla niestandardowego Viewpagera, który będzie powiększał fragment w miarę przesuwania ostrości i zmniejszał go w miarę przesuwania się poza ostrość. Poza klasami Adapter i Fragment mam tutaj wszystko, czego potrzebujesz, to aktywność rodzica, aby móc odwołać się do zmiennej adapter i jesteś ustawiony.

Adapter

public class GrowPagerAdapter extends FragmentPagerAdapter implements OnPageChangeListener, OnScrollChangedListener {

public final String TAG = this.getClass().getSimpleName();

private final int COUNT = 4;

public static final float BASE_SIZE = 0.8f;
public static final float BASE_ALPHA = 0.8f;

private int mCurrentPage = 0;
private boolean mScrollingLeft;

private List<SummaryTabletFragment> mFragments;

public int getCurrentPage() {
    return mCurrentPage;
}

public void addFragment(SummaryTabletFragment fragment) {
    mFragments.add(fragment.getPosition(), fragment);
}

public GrowPagerAdapter(FragmentManager fm) {
    super(fm);

    mFragments = new ArrayList<SummaryTabletFragment>();
}

@Override
public int getCount() {
    return COUNT;
}

@Override
public Fragment getItem(int position) {
    return SummaryTabletFragment.newInstance(position);
}

@Override
public void onPageScrollStateChanged(int state) {}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    adjustSize(position, positionOffset);
}

@Override
public void onPageSelected(int position) {
    mCurrentPage = position;
}

/**
 * Used to adjust the size of each view in the viewpager as the user
 * scrolls.  This provides the effect of children scaling down as they
 * are moved out and back to full size as they come into focus.
 * 
 * @param position
 * @param percent
 */
private void adjustSize(int position, float percent) {

    position += (mScrollingLeft ? 1 : 0);
    int secondary = position + (mScrollingLeft ? -1 : 1);
    int tertiary = position + (mScrollingLeft ? 1 : -1);

    float scaleUp = mScrollingLeft ? percent : 1.0f - percent;
    float scaleDown = mScrollingLeft ? 1.0f - percent : percent;

    float percentOut = scaleUp > BASE_ALPHA ? BASE_ALPHA : scaleUp;
    float percentIn = scaleDown > BASE_ALPHA ? BASE_ALPHA : scaleDown;

    if (scaleUp < BASE_SIZE)
        scaleUp = BASE_SIZE;

    if (scaleDown < BASE_SIZE)
        scaleDown = BASE_SIZE;

    // Adjust the fragments that are, or will be, on screen
    SummaryTabletFragment current = (position < mFragments.size()) ? mFragments.get(position) : null;
    SummaryTabletFragment next = (secondary < mFragments.size() && secondary > -1) ? mFragments.get(secondary) : null;
    SummaryTabletFragment afterNext = (tertiary < mFragments.size() && tertiary > -1) ? mFragments.get(tertiary) : null;

    if (current != null && next != null) {

        // Apply the adjustments to each fragment
        current.transitionFragment(percentIn, scaleUp);
        next.transitionFragment(percentOut, scaleDown);

        if (afterNext != null) {
            afterNext.transitionFragment(BASE_ALPHA, BASE_SIZE);
        }
    }
}

@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {

    // Keep track of which direction we are scrolling
    mScrollingLeft = (oldl - l) < 0;
}
}

Fragment

public class SummaryTabletFragment extends BaseTabletFragment {

public final String TAG = this.getClass().getSimpleName();

private final float SCALE_SIZE = 0.8f;

private RelativeLayout mBackground, mCover;
private TextView mTitle;
private VerticalTextView mLeft, mRight;

private String mTitleText;
private Integer mColor;

private boolean mInit = false;
private Float mScale, mPercent;

private GrowPagerAdapter mAdapter;
private int mCurrentPosition = 0;

public String getTitleText() {
    return mTitleText;
}

public void setTitleText(String titleText) {
    this.mTitleText = titleText;
}

public static SummaryTabletFragment newInstance(int position) {

    SummaryTabletFragment fragment = new SummaryTabletFragment();
    fragment.setRetainInstance(true);

    Bundle args = new Bundle();
    args.putInt("position", position);
    fragment.setArguments(args);

    return fragment;
}

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

    mRoot = inflater.inflate(R.layout.tablet_dummy_view, null);

    setupViews();
    configureView();

    return mRoot;
}

@Override
public void onViewStateRestored(Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);

    if (savedInstanceState != null) {
        mColor = savedInstanceState.getInt("color", Color.BLACK);
    }

    configureView();
}

@Override
public void onSaveInstanceState(Bundle outState)  {

    outState.putInt("color", mColor);

    super.onSaveInstanceState(outState);
}

@Override
public int getPosition() {
    return getArguments().getInt("position", -1);
}

@Override
public void setPosition(int position) {
    getArguments().putInt("position", position);
}

public void onResume() {
    super.onResume();

    mAdapter = mActivity.getPagerAdapter();
    mAdapter.addFragment(this);
    mCurrentPosition = mAdapter.getCurrentPage();

    if ((getPosition() == (mCurrentPosition + 1) || getPosition() == (mCurrentPosition - 1)) && !mInit) {
        mInit = true;
        transitionFragment(GrowPagerAdapter.BASE_ALPHA, GrowPagerAdapter.BASE_SIZE);
        return;
    }

    if (getPosition() == mCurrentPosition && !mInit) {
        mInit = true;
        transitionFragment(0.00f, 1.0f);
    }
}

private void setupViews() {

    mCover = (RelativeLayout) mRoot.findViewById(R.id.cover);
    mLeft = (VerticalTextView) mRoot.findViewById(R.id.title_left);
    mRight = (VerticalTextView) mRoot.findViewById(R.id.title_right);
    mBackground = (RelativeLayout) mRoot.findViewById(R.id.root);
    mTitle = (TextView) mRoot.findViewById(R.id.title);
}

private void configureView() {

    Fonts.applyPrimaryBoldFont(mLeft, 15);
    Fonts.applyPrimaryBoldFont(mRight, 15);

    float[] size = UiUtils.getScreenMeasurements(mActivity);
    int width = (int) (size[0] * SCALE_SIZE);
    int height = (int) (size[1] * SCALE_SIZE);

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height);
    mBackground.setLayoutParams(params);

    if (mScale != null)
        transitionFragment(mPercent, mScale);

    setRandomBackground();

    setTitleText("Fragment " + getPosition());

    mTitle.setText(getTitleText().toUpperCase());
    mLeft.setText(getTitleText().toUpperCase());
    mRight.setText(getTitleText().toUpperCase());

    mLeft.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            mActivity.showNextPage();
        }
    });

    mRight.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            mActivity.showPrevPage();
        }
    });
}

private void setRandomBackground() {

    if (mColor == null) {
        Random r = new Random();
        mColor = Color.rgb(r.nextInt(255), r.nextInt(255), r.nextInt(255));
    }

    mBackground.setBackgroundColor(mColor);
}

public void transitionFragment(float percent, float scale) {

    this.mScale = scale;
    this.mPercent = percent;

    if (getView() != null && mCover != null) {

        getView().setScaleX(scale);
        getView().setScaleY(scale);

        mCover.setAlpha(percent);
        mCover.setVisibility((percent <= 0.05f) ? View.GONE : View.VISIBLE);
    }
}

@Override
public String getFragmentTitle() {
    return null;
}
}
 0
Author: saulpower,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 04:12:22

Moje rozwiązanie: ustawiam prawie każdy Widok jako static. Teraz moja aplikacja współdziała idealnie. Możliwość wywoływania statycznych metod zewsząd nie jest może dobrym stylem, ale po co bawić się kodem, który nie działa? Przeczytałem tu wiele pytań i odpowiedzi na nie i żadne rozwiązanie nie przyniosło sukcesu (dla mnie).

Wiem, że może wyciekać pamięć i marnować kupę, a mój kod nie będzie pasował do innych projektów, ale nie boję się tego - testowałem aplikację na różnych urządzeniach i warunki, żadnych problemów, Platforma Android wydaje się być w stanie sobie z tym poradzić. Interfejs użytkownika jest odświeżany co sekundę, a nawet na urządzeniu S2 ICS (4.0.3) aplikacja jest w stanie obsłużyć tysiące geo-markerów.

 0
Author: Martin Pfeffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-18 22:17:49

Spotkałem się z tym samym problemem, ale mój ViewPager znajdował się wewnątrz TopFragment, który stworzył i ustawił adapter za pomocą setAdapter(new FragmentPagerAdapter(getChildFragmentManager())).

Naprawiłem ten problem poprzez nadpisanie onAttachFragment(Fragment childFragment) w TopFragment tak:

@Override
public void onAttachFragment(Fragment childFragment) {
    if (childFragment instanceof OnboardingDiamondsFragment) {
        mChildFragment = (ChildFragment) childFragment;
    }

    super.onAttachFragment(childFragment);
}

Jak już wiadomo (Zobacz odpowiedzi powyżej), gdy childFragmentManager się odtwarza, tworzy również fragmenty, które znajdowały się wewnątrz viewpagera.
Ważne jest to, że po tym wywołuje onAttachFragment i teraz mamy odniesienie do nowego odtworzonego fragment!

Mam nadzieję, że to pomoże każdemu dostać to stare Q jak ja:)

 0
Author: Shirane85,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-05 14:40:56

Rozwiązałem problem zapisując fragmenty w SparceArray:

public abstract class SaveFragmentsPagerAdapter extends FragmentPagerAdapter {

    SparseArray<Fragment> fragments = new SparseArray<>();

    public SaveFragmentsPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.append(position, fragment);
        return fragment;
    }

    @Nullable
    public Fragment getFragmentByPosition(int position){
        return fragments.get(position);
    }

}
 0
Author: xaxtix,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-14 15:37:47

Tak dla twojej wiadomości...

Dodając do litanii nieszczęść z tymi klasami, jest dość ciekawy błąd, którym warto się podzielić.

Używam Viewpagera do poruszania się po drzewie elementów (zaznacz element, a view pager ożywia przewijanie w prawo, pojawia się następna gałąź, nawigacja z powrotem, a ViewPager przewija się w przeciwnym kierunku, aby powrócić do poprzedniego węzła).

Problem pojawia się, gdy wciskam i wyskakuję fragmenty z końca / Align = "center" bgcolor = "# e0ffe0 " / cesarz chin / / align = center / Jest wystarczająco inteligentny, aby zauważyć, że elementy się zmieniają, i wystarczająco inteligentny, aby utworzyć i zastąpić fragment, gdy element się zmienił. Ale nie na tyle inteligentny, aby odrzucić stan fragmentu lub wystarczająco inteligentny, aby przyciąć wewnętrznie zapisane stany fragmentu, gdy zmieni się rozmiar adaptera. Więc kiedy pop elementu i wcisnąć nowy na końcu, fragment dla nowego elementu dostaje zapisany stan fragmentu dla starego elementu, co spowodowało absolutne spustoszenie w moim kodzie. Moje fragmenty przenoszenie danych, które mogą wymagać dużo pracy, aby refetch z internetu, więc nie zapisywanie stanu naprawdę nie było opcją.

Nie mam czystego obejścia. Użyłem czegoś takiego:
  public void onSaveInstanceState(Bundle outState) {
    IFragmentListener listener = (IFragmentListener)getActivity();
    if (listener!= null)
    {
        if (!listener.isStillInTheAdapter(this.getAdapterItem()))
        {
            return; // return empty state.
        }

    }
    super.onSaveInstanceState(outState);

    // normal saving of state for flips and 
    // paging out of the activity follows
    ....
  }

Niedoskonałe rozwiązanie, ponieważ nowa instancja fragmentu nadal otrzymuje pakiet savedState, ale przynajmniej nie zawiera starych danych.

 0
Author: Robin Davies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-16 00:48:49

Ponieważ ludzie nie czytają komentarzy, oto odpowiedź, która w większości dubluje to, co napisałem tutaj :

Główną przyczyną problemu jest fakt, że system android nie wywołuje getItem, Aby uzyskać fragmenty, które są rzeczywiście wyświetlane, ale instantiateItem. Ta metoda najpierw próbuje wyszukać i ponownie użyć instancji fragmentu dla danej karty w FragmentManager. Tylko jeśli to wyszukiwanie nie powiedzie się (co dzieje się tylko za pierwszym razem, gdy FragmentManager jest nowo utworzona), wtedy zostanie wywołane getItem. To dla oczywistych powody, aby nie odtwarzać fragmentów (które mogą być ciężkie), na przykład za każdym razem, gdy użytkownik obraca swoje urządzenie.
Aby rozwiązać ten problem, zamiast tworzyć fragmenty za pomocą Fragment.instantiate w aktywności, powinieneś to zrobić za pomocą pagerAdapter.instantiateItem i wszystkie te wywołania powinny być otoczone wywołaniami metody startUpdate/finishUpdate, które odpowiednio rozpoczynają / zatwierdzają transakcję fragmentu. getItem powinno być miejscem, w którym fragmenty są naprawdę tworzone przy użyciu odpowiednich konstruktorów.

List<Fragment> fragments = new Vector<Fragment>();

@Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);
        ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);

        adapter.startUpdate(viewPager);
        fragments.add(adapter.instantiateItem(viewPager, 0));
        fragments.add(adapter.instantiateItem(viewPager, 1));
        // and so on if you have more tabs...
        adapter.finishUpdate(viewPager);
}

class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager manager) {super(manager);}

        @Override public int getCount() {return 2;}

        @Override public Fragment getItem(int position) {
            if (position == 0) return new Fragment0();
            if (position == 1) return new Fragment1();
            return null;  // or throw some exception
        }

        @Override public CharSequence getPageTitle(int position) {
            if (position == 0) return getString(R.string.tab0);
            if (position == 1) return getString(R.string.tab1);
            return null;  // or throw some exception
        }
}
 0
Author: morgwai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-10 20:11:45