поддержка FragmentPagerAdapter содержит ссылку на старые фрагменты - PullRequest
105 голосов
/ 15 марта 2012

ПОСЛЕДНЯЯ ИНФОРМАЦИЯ:

Я сузил свою проблему до проблемы, связанной с сохранением в фрагменте фрагмента фрагментов фрагмента старых фрагментов и тем, что мой просмотрщик не синхронизирован с моим FragmentManager.Смотрите этот выпуск ... http://code.google.com/p/android/issues/detail?id=19211#makechanges.Я до сих пор не знаю, как решить эту проблему.Любые предложения ...

Я пытался отладить это в течение длительного времени, и любая помощь будет принята с благодарностью.Я использую FragmentPagerAdapter, который принимает список фрагментов примерно так:

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

Реализация стандартная.Я использую ActionBarSherlock и v4 библиотеку вычислимости для фрагментов.

Моя проблема заключается в том, что после выхода из приложения, открытия нескольких других приложений и возврата фрагменты теряют свою ссылку обратно на FragmentActivity (т. Е. getActivity() == null),Я не могу понять, почему это происходит.Я пытался вручную установить setRetainInstance(true);, но это не помогает.Я полагал, что это происходит, когда моя FragmentActivity разрушается, однако это все равно происходит, если я открываю приложение до того, как получаю сообщение журнала.Есть какие-нибудь идеи?

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

Адаптер:

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();

    }

}

Один из моих фрагментов разорван, но я комментировал все, что разобрано и до сих пор не работает ...

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);
    }

}

}

Метод обновления вызывается, когда пользователь взаимодействует с другим фрагментом, а getActivity возвращает ноль.Вот метод, который вызывает другой фрагмент ...

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

Я полагаю, что когда приложение уничтожается, затем создается снова, вместо того, чтобы просто запустить приложение до фрагмента по умолчанию, приложение запускается, а затем в viewpagerПереходит к последней известной странице.Это кажется странным, разве приложение не должно просто загружаться во фрагмент по умолчанию?

Ответы [ 13 ]

0 голосов
/ 05 февраля 2017

Я столкнулся с той же проблемой, но мой ViewPager был внутри TopFragment, который создал и установил адаптер, используя setAdapter(new FragmentPagerAdapter(getChildFragmentManager())).

Я исправил эту проблему, переопределив onAttachFragment(Fragment childFragment) в TopFragment, как это:

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

    super.onAttachFragment(childFragment);
}

Как уже известно (см. Ответы выше), когда childFragmentManager воссоздает себя, он также создает фрагменты, которые были внутри viewPager.
Важной частью является то, что после этого он вызывает onAttachFragment и теперь у нас есть ссылка на новый воссозданный фрагмент!

Надеюсь, это поможет любому получить этот старый Q, как я:)

0 голосов
/ 12 ноября 2014

Мое решение: я установил почти каждый просмотр как static. Теперь мое приложение взаимодействует идеально. Возможность вызывать статические методы из любого места, возможно, не очень хороший стиль, но зачем играть с кодом, который не работает? Я прочитал много вопросов и их ответов здесь, на SO, и ни одно решение не принесло успеха (для меня).

Я знаю, что это может привести к утечке памяти и потере кучи, и мой код не подойдет для других проектов, но я не боюсь этого - я тестировал приложение на разных устройствах и в любых условиях, проблем вообще нет Платформа Android, кажется, способна справиться с этим. Пользовательский интерфейс обновляется каждую секунду, и даже на устройстве S2 ICS (4.0.3) приложение может обрабатывать тысячи геомаркеров.

0 голосов
/ 10 декабря 2012

Поскольку FragmentManager позаботится о восстановлении фрагментов для вас, как только будет вызван метод onResume (), у меня есть фрагмент для вызова действия и добавления себя в список.В моем случае я храню все это в моей реализации PagerAdapter.Каждый фрагмент знает свою позицию, потому что он добавляется к аргументам фрагмента при создании.Теперь, когда мне нужно манипулировать фрагментом по определенному индексу, все, что мне нужно сделать, это использовать список из моего адаптера.

Ниже приведен пример адаптера для пользовательского ViewPager, который будет увеличивать фрагмент по мере егоперемещается в фокус и уменьшает его, когда он выходит из фокуса.Помимо классов «Адаптер» и «Фрагмент», которые у меня есть, все, что вам нужно, это чтобы родительское действие могло ссылаться на переменную адаптера, и вы настроены.

Адаптер

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;
}
}

Фрагмент

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;
}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...