16

我創建了一個使用FragmentStatePagerAdapter提供小型圖庫的活動。但是,當活動恢復時(例如,從其他活動返回後),我無法恢復它。每次前兩張照片都是空白的,只有在我將兩張照片刷到一邊後,纔會刷新。我找到工作的答案(尤其是壓倒一切的getItemPosition())的無在恢復活動時刷新FragmentStatePagerAdapter上的圖像

我把它像這樣:

mPagerAdapter = new PhotosPagerAdapter(getSupportFragmentManager()); 
mPager = (ViewPager) findViewById(R.id.photosViewPager); 
mPager.setAdapter(mPagerAdapter); 

然後,我有FragmentStatePagerAdapter類:

private class PhotosPagerAdapter extends FragmentStatePagerAdapter{ 

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

    @Override 
    public int getCount() { 
     return photos.size(); 
    } 

    @Override 
    public Fragment getItem(int position) { 
     ImageFragment f = new ImageFragment(position); 
     return f; 
    } 

    @Override 
    public int getItemPosition(Object object) { 
     throw new RuntimeException(); 
     //return POSITION_NONE; 
    } 

} 

正如你可能已經注意到,我在getItemPosition中拋出了RuntimeException,因爲我想檢查它何時被調用。直到我添加包含我的照片的列表才能調用它。然後ImageFragment類:

public class ImageFragment extends Fragment{ 

    int position; 
    Bitmap mBitmap; 
    int width; 
    int height; 
    ImageView img; 

    public ImageFragment(){ 
    } 

    public ImageFragment(int position){ 
     this.position = position; 
    } 

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

     img = new ImageView(container.getContext()); 
     img.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); 
     width = container.getWidth(); 
     height = container.getHeight(); 

     loadBitmap(); 

     return img; 
    }  

    public void loadBitmap(){ 
     if (img == null){ 
      return; 
     } 
     final BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inJustDecodeBounds = true; 
     BitmapFactory.decodeFile(photos.get(position), options); 
     options.inSampleSize = calculateInSampleSize(options, width/2, height/2); 
     options.inJustDecodeBounds = false; 
     mBitmap = BitmapFactory 
       .decodeFile(photos.get(position), options);   

     img.setImageBitmap(mBitmap); 
    } 


    @Override 
    public void onDestroyView() { 
     mBitmap.recycle(); 
     super.onDestroyView(); 
    }  
} 

代碼是有點亂後,我試圖修復它......但是:除去onDestroyView()不起作用。我已將mPagerAdapter.notifyDataSetChanged()放在必須呼叫的幾個地方(如onResume()),但沒有結果。我對此感到絕望。

回答

31

處理片段尋呼機適配器可以是PITA。

這裏有一些有用的提示:

ViewPager PagerAdapter not updating the View

Update ViewPager dynamically?

一般來說這一個工程的99%的時間......

覆蓋getItemPosition在PagerAdapter這樣的:

@Override 
public int getItemPosition(Object object) { 
    return POSITION_NONE; 
} 

有時甚至那些不工作,我不得不使用'蠻力'的方法,並再次重新創建整個視圖(從onCreate起)...

+0

你是個天才!我整天都在試一切,但這已經很完美了! –

+0

與適配器的notifyDataSetChanged()調用對應。 – user465363

1

決不只是用POSITION_NONE使用

if(fragmentManager.getFragments().contains(object)) 
    return POSITION_NONE; 
else 
    return POSITION_UNCHANGED; 

,以避免致命的異常:java.lang.IllegalStateException 片段{}不是目前在FragmentManager

+0

它不適用於我 –

4

我有類似的問題,你的一些研究後,我創建了一個很好的腳本,避免重新創建已經存在的碎片,但同時允許您更新所有可見/啓動的碎片。

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentStatePagerAdapter; 
import android.view.ViewGroup; 

import java.util.WeakHashMap; 

/** 
* Created by TheCobra on 9/17/15. 
*/ 
public abstract class FragmentAdvanceStatePagerAdapter extends FragmentStatePagerAdapter 
{ 
    private WeakHashMap<Integer, Fragment> mFragments; 

    public FragmentAdvanceStatePagerAdapter(FragmentManager fm) 
    { 
     super(fm); 
     mFragments = new WeakHashMap<Integer, Fragment>(); 
    } 

    @Override 
    public Fragment getItem(int position) 
    { 
     Fragment item = getFragmentItem(position); 
     mFragments.put(Integer.valueOf(position), item); 
     return item; 
    } 

    @Override 
    public void destroyItem(ViewGroup container, int position, Object object) 
    { 
     super.destroyItem(container, position, object); 
     Integer key = Integer.valueOf(position); 
     if (mFragments.containsKey(key)) 
     { 
      mFragments.remove(key); 
     } 
    } 

    @Override 
    public void notifyDataSetChanged() 
    { 
     super.notifyDataSetChanged(); 
     for (Integer position : mFragments.keySet()) 
     { 
      //Make sure we only update fragments that should be seen 
      if (position != null && mFragments.get(position) != null && position.intValue() < getCount()) 
      { 
       updateFragmentItem(position, mFragments.get(position)); 
      } 
     } 
    } 

    @Override 
    public int getItemPosition(Object object) 
    { 
     //If the object is a fragment, check to see if we have it in the hashmap 
     if (object instanceof Fragment) 
     { 
      int position = findFragmentPositionHashMap((Fragment) object); 
      //If fragment found in the hashmap check if it should be shown 
      if (position >= 0) 
      { 
       //Return POSITION_NONE if it shouldn't be display 
       return (position >= getCount()? POSITION_NONE : position); 
      } 
     } 

     return super.getItemPosition(object); 
    } 

    /** 
    * Find the location of a fragment in the hashmap if it being view 
    * @param object the Fragment we want to check for 
    * @return the position if found else -1 
    */ 
    protected int findFragmentPositionHashMap(Fragment object) 
    { 
     for (Integer position : mFragments.keySet()) 
     { 
      if (position != null && 
       mFragments.get(position) != null && 
       mFragments.get(position) == object) 
      { 
       return position; 
      } 
     } 

     return -1; 
    } 

    public abstract Fragment getFragmentItem(int position); 
    public abstract void updateFragmentItem(int position, Fragment fragment); 
} 

將該代碼複製到文件名「FragmentAdvanceStatePagerAdapter.java」中。現在在你的適配器中,從這個擴展並覆蓋「getFragmentItem()」&「updateFragmentItem()」。無論何時調用notifydatachange(),updateFragmentItem()都將在所有已創建的片段被調用。當適配器需要創建一個新的片段時,getFragmentItem()將被調用。

我希望保存,並幫助了很多人:)

好運和快樂編程!

P.S.如果你使用這個類,你的適配器「getItem()」應該是「getFragmentItem()」。

+0

我已更新,修復了我在代碼中發現的錯誤。 – TheCobra

+0

驚人的代碼!它的作用就像一種魅力。這裏最好的答案 – davidrelgr