2012-11-07 154 views
1

我有一個Activity,其中ViewPager中包含一些Fragment。這裏是適配器(該mFooFragment的是Activity成員從活動獲取ViewPager片段

private class HomePagerAdapter extends FragmentPagerAdapter 
{ 
    public HomePagerAdapter(FragmentManager fm) 
    { 
     super(fm); 
    } 

    @Override 
    public Fragment getItem(int position) 
    { 
     switch (position) 
     { 
     case 0: 
      mSellingFragment = new SellingFragment(); 
      return mSellingFragment; 
     case 1: 
      mSearchFragment = new SearchFragment(); 
      return mSearchFragment; 
     case 2: 
      mProfileFragment = new ProfileFragment(); 
      return mProfileFragment; 
     } 
     return null; 
    } 

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

再後來我做的東西一樣:

mSellingFragment.refresh(); 

不幸的是,會員片段可以null一種情況我。確定並且可以檢查 - 頁面被延遲加載,所以它們在顯示之前不可用。但是,沒關係,我只希望refresh()在可見頁面上起作用

但是有時它們是null即使可見。我認爲正在發生的事情是這樣的:

我的片段具有setRetainInstance(true)所以,當我瀏覽從它被摧毀的活動遠,但片段保留,然後當我回去吧,活性重建與不知何故,舊的片段和getItem()永遠不會被調用,所以mFooFragment從未設置。

是嗎?一個人應該如何處理這個問題?我可以想到的一種方法是將setFooFragment(FooFragment f) { mFooFragment = f; }函數加載到活動中,並從FooFragment.onAttach()調用它們,但必須有更好的方法!

編輯

我擡頭的FragmentPagerAdapter的源代碼(往往能得到在Android的土地答案的唯一途徑!),它的確是這樣的,它節省了片段:

@Override 
public Object instantiateItem(View container, int position) { 
    if (mCurTransaction == null) { 
     mCurTransaction = mFragmentManager.beginTransaction(); 
    } 

    // Do we already have this fragment? 
    String name = makeFragmentName(container.getId(), position); 
    Fragment fragment = mFragmentManager.findFragmentByTag(name); 
    if (fragment != null) { 
     if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment); 
     mCurTransaction.attach(fragment); 
    } else { 
     fragment = getItem(position); 
     if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); 
     mCurTransaction.add(container.getId(), fragment, 
       makeFragmentName(container.getId(), position)); 
    } 
    if (fragment != mCurrentPrimaryItem) { 
     fragment.setMenuVisibility(false); 
    } 

    return fragment; 
} 

不幸的是,它不會使那些重新附加Fragment可用於子類!

回答

0

我目前的,有點冒失的解決方案是複製FragmentPagerAdapter併爲添加片段添加處理程序:void onItemCreated(Fragment fragment, int position)然後您可以在自定義尋呼機適配器中重寫以將片段保存爲成員變量。下面的完整代碼(未測試過!)

/* 
* Copyright (C) 2011 The Android Open Source Project 
* 
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
*  http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
*/ 

package com.your.package.name; 

import android.os.Parcelable; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentStatePagerAdapter; 
import android.support.v4.app.FragmentTransaction; 
import android.support.v4.view.PagerAdapter; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewGroup; 

/** 
* Implementation of {@link android.support.v4.view.PagerAdapter} that 
* represents each page as a {@link Fragment} that is persistently 
* kept in the fragment manager as long as the user can return to the page. 
* 
* <p>This version of the pager is best for use when there are a handful of 
* typically more static fragments to be paged through, such as a set of tabs. 
* The fragment of each page the user visits will be kept in memory, though its 
* view hierarchy may be destroyed when not visible. This can result in using 
* a significant amount of memory since fragment instances can hold on to an 
* arbitrary amount of state. For larger sets of pages, consider 
* {@link FragmentStatePagerAdapter}. 
* 
* <p>When using FragmentPagerAdapter the host ViewPager must have a 
* valid ID set.</p> 
* 
* <p>Subclasses only need to implement {@link #getItem(int)} 
* and {@link #getCount()} to have a working adapter. 
* 
* <p>Here is an example implementation of a pager containing fragments of 
* lists: 
* 
* {@sample development/samples/Support4Demos/src/com/example/android/supportv4/app/FragmentPagerSupport.java 
*  complete} 
* 
* <p>The <code>R.layout.fragment_pager</code> resource of the top-level fragment is: 
* 
* {@sample development/samples/Support4Demos/res/layout/fragment_pager.xml 
*  complete} 
* 
* <p>The <code>R.layout.fragment_pager_list</code> resource containing each 
* individual fragment's layout is: 
* 
* {@sample development/samples/Support4Demos/res/layout/fragment_pager_list.xml 
*  complete} 
*/ 
public abstract class FragmentPagerAdapter extends PagerAdapter { 
    private static final String TAG = "FragmentPagerAdapter"; 
    private static final boolean DEBUG = false; 

    private final FragmentManager mFragmentManager; 
    private FragmentTransaction mCurTransaction = null; 
    private Fragment mCurrentPrimaryItem = null; 

    public FragmentPagerAdapter(FragmentManager fm) { 
     mFragmentManager = fm; 
    } 

    /** 
    * Return the Fragment associated with a specified position. 
    */ 
    public abstract Fragment getItem(int position); 

    @Override 
    public void startUpdate(ViewGroup container) { 
    } 

    @Override 
    public Object instantiateItem(ViewGroup container, int position) { 
     if (mCurTransaction == null) { 
      mCurTransaction = mFragmentManager.beginTransaction(); 
     } 

     final long itemId = getItemId(position); 

     // Do we already have this fragment? 
     String name = makeFragmentName(container.getId(), itemId); 
     Fragment fragment = mFragmentManager.findFragmentByTag(name); 
     if (fragment != null) { 
      if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment); 
      mCurTransaction.attach(fragment); 
     } else { 
      fragment = getItem(position); 
      if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment); 
      mCurTransaction.add(container.getId(), fragment, 
        makeFragmentName(container.getId(), itemId)); 
     } 
     if (fragment != mCurrentPrimaryItem) { 
      fragment.setMenuVisibility(false); 
      fragment.setUserVisibleHint(false); 
     } 

     onItemCreated(fragment, position); 
     return fragment; 
    } 

    /** 
    * Called when a fragment has been created/attached. 
    */ 
    public abstract void onItemCreated(Fragment fragment, int position); 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) { 
     if (mCurTransaction == null) { 
      mCurTransaction = mFragmentManager.beginTransaction(); 
     } 
     if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object 
       + " v=" + ((Fragment)object).getView()); 
     mCurTransaction.detach((Fragment)object); 
    } 

    @Override 
    public void setPrimaryItem(ViewGroup container, int position, Object object) { 
     Fragment fragment = (Fragment)object; 
     if (fragment != mCurrentPrimaryItem) { 
      if (mCurrentPrimaryItem != null) { 
       mCurrentPrimaryItem.setMenuVisibility(false); 
       mCurrentPrimaryItem.setUserVisibleHint(false); 
      } 
      if (fragment != null) { 
       fragment.setMenuVisibility(true); 
       fragment.setUserVisibleHint(true); 
      } 
      mCurrentPrimaryItem = fragment; 
     } 
    } 

    @Override 
    public void finishUpdate(ViewGroup container) { 
     if (mCurTransaction != null) { 
      mCurTransaction.commitAllowingStateLoss(); 
      mCurTransaction = null; 
      mFragmentManager.executePendingTransactions(); 
     } 
    } 

    @Override 
    public boolean isViewFromObject(View view, Object object) { 
     return ((Fragment)object).getView() == view; 
    } 

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

    @Override 
    public void restoreState(Parcelable state, ClassLoader loader) { 
    } 

    /** 
    * Return a unique identifier for the item at the given position. 
    * 
    * <p>The default implementation returns the given position. 
    * Subclasses should override this method if the positions of items can change.</p> 
    * 
    * @param position Position within this adapter 
    * @return Unique identifier for the item at position 
    */ 
    public long getItemId(int position) { 
     return position; 
    } 

    private static String makeFragmentName(int viewId, long id) { 
     return "android:switcher:" + viewId + ":" + id; 
    } 
}