您的位置:首页 > 移动开发 > Android开发

Android-ViewPager+Fragment数据更新问题

2016-11-18 17:30 459 查看
因为FragmentPagerAdapter内部存在缓存,因此调用notifyDataSetChanged()并不能够去更新Fragment的内容。

参考:http://www.devba.com/index.php/archives/5826.html

http://stackoverflow.com/questions/7263291/viewpager-pageradapter-not-updating-the-view/7287121#7287121

可以有两种解决办法:

(1)重写Adapter的getItemPosition():

[java]
view plain
copy

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

当调用notifyDataSetChanged()的时候,ViewPager会remove掉所有的view,然后重新去加载。可行,但是效率低。
(2)在view上调用SetTag,然后用ViewPager.findViewWithTag()来找到要更新的view,然后做更新。

因为FragmentPagerAdapter内部缓存Fragment的时候,已经是按照tag的方式缓存的,因此,在更新的时候,我们只要根据tag,拿到fragment,然后去更新fragment就可以了。

看下FragmentPagerAdapter的instantiateItem()方法:

[java]
view plain
copy

public Object instantiateItem(ViewGroup container, int position)  
  {  
    if (this.mCurTransaction == null) {  
      this.mCurTransaction = this.mFragmentManager.beginTransaction();  
    }  
  
    long itemId = getItemId(position);  
  
    String name = makeFragmentName(container.getId(), itemId);//这里就是在生成fragment的tag  
    Fragment fragment = this.mFragmentManager.findFragmentByTag(name);//这里是根据tag查找  
    if (fragment != null)  
    {  
      this.mCurTransaction.attach(fragment);//找到直接attch  
    } else {  
      fragment = getItem(position);//找不到的时候,才会调用getItem  
  
      this.mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));  
    }  
  
    if (fragment != this.mCurrentPrimaryItem) {  
      fragment.setMenuVisibility(false);  
      fragment.setUserVisibleHint(false);  
    }  
  
    return fragment;  
  }  

根据原代码我们可以知道系统给每一个Fragment都打上了一个标签,通过标签来寻找相应的fragment,所以当我们第二次进入fragment的时候,fragment的oncreate,oncreateView方法都不会被调用的,因为FragmentPageAdapter中的getitem()方法根本不会被调用,因为系统会根据标签找到相应的fragment,如果已经存在,就不会被调用,fragment有一个缓存机制在这里。

现在的问题是必须要做更新,那么可以这么弄:

[java]
view plain
copy

public class FragmentViewPagerAdapter extends FragmentPagerAdapter {  
      
    private FragmentManager mFragmentManager;  
    private List<String> mDatas;  
    private List<String> tagList = new ArrayList<String>();  
  
    public FragmentViewPagerAdapter(FragmentManager fm, List<String> datas) {  
        super(fm);  
        this.mFragmentManager = fm;  
        this.mDatas = datas;  
    }  
      
    @Override  
    public Object instantiateItem(ViewGroup container, int position) {      
        tagList.add(makeFragmentName(container.getId(), getItemId(position))); //把tag存起来     
        return super.instantiateItem(container, position);      
    }   
      
    @Override  
    public void destroyItem(ViewGroup container, int position, Object object){  
        super.destroyItem(container, position, object);  
        tagList.remove(makeFragmentName(container.getId(), getItemId(position)));//把tag删掉  
    }  
      
    @Override  
    public Fragment getItem(int position) {  
        String url = mDatas.get(position);  
        WebViewFragmentV4 webview = new WebViewFragmentV4(url);//本文测试的Fragment是一个WebViewFragment  

[java]
view plain
copy

        return webview;  
    }  
  
    @Override  
    public int getCount() {  
        if (mDatas == null) {  
            return 0;  
        } else {  
            return mDatas.size();  
        }  
    }  
  
    public void update(List<String> datas){  
        this.mDatas = datas;  
        notifyDataSetChanged();//并不能起到更新Fragment内容的作用。  
    }  
      
    public void update(int position){//这个事真正的更新Fragment的内容  
        WebViewFragmentV4 fragment = (WebViewFragmentV4)mFragmentManager.findFragmentByTag(tagList.get(position));    
        if(fragment == null){  
            return;  
        }  
        fragment.update();  
    }  
  
    private static String makeFragmentName(int viewId, long id) {  
        return "android:switcher:" + viewId + ":" + id;  
    }  
}  

WebViewFragmentV4.java:

[java]
view plain
copy

public class WebViewFragmentV4 extends Fragment {  
    private WebView mWebView;  
    private boolean mIsWebViewAvailable;  
    private String mUrl;  
    public WebViewFragmentV4(String url) {  
        this.mUrl = url;  
    }  
  
    /** 
     * Called to instantiate the view. Creates and returns the WebView. 
     */  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container,  
            Bundle savedInstanceState) {  
        if (mWebView != null) {  
            mWebView.destroy();  
        }  
        mWebView = new WebView(getActivity());  
        mWebView.getSettings().setUseWideViewPort(true);  
        mWebView.getSettings().setLoadWithOverviewMode(true);   
        mWebView.setWebViewClient(new MyWebViewClient());  
        mWebView.loadUrl(mUrl);  
        mIsWebViewAvailable = true;  
        return mWebView;  
    }  
  
    /** 
     * Called when the fragment is visible to the user and actively running. 
     * Resumes the WebView. 
     */  
    @Override  
    public void onPause() {  
        super.onPause();  
        mWebView.onPause();  
    }  
  
    /** 
     * Called when the fragment is no longer resumed. Pauses the WebView. 
     */  
    @Override  
    public void onResume() {  
        mWebView.onResume();  
        super.onResume();  
    }  
  
    /** 
     * Called when the WebView has been detached from the fragment. The WebView 
     * is no longer available after this time. 
     */  
    @Override  
    public void onDestroyView() {  
        mIsWebViewAvailable = false;  
        super.onDestroyView();  
    }  
  
    /** 
     * Called when the fragment is no longer in use. Destroys the internal state 
     * of the WebView. 
     */  
    @Override  
    public void onDestroy() {  
        if (mWebView != null) {  
            mWebView.destroy();  
            mWebView = null;  
        }  
        super.onDestroy();  
    }  
  
    public void update(){  
        if (mWebView != null) {  
            mWebView.reload();  
        }  
    }  
      
    /** 
     * Gets the WebView. 
     */  
    public WebView getWebView() {  
        return mIsWebViewAvailable ? mWebView : null;  
    }  
      
    private static class MyWebViewClient extends WebViewClient {  
          
        @Override  
        public boolean shouldOverrideUrlLoading(WebView view, String url) {  
            view.loadUrl(url);  
            return true;  
        }  
  
        @Override  
        public void onPageStarted(WebView view, String url, Bitmap favicon) {  
            super.onPageStarted(view, url, favicon);  
        }  
          
        @Override  
        public void onPageFinished(WebView view, String url) {  
            super.onPageFinished(view, url);  
        }  
  
        @Override  
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {  
            super.onReceivedError(view, errorCode, description, failingUrl);  
        }  
    }  
}  

转载请标明出处:http://blog.csdn.net/goldenfish1919/article/details/47661443

测试代码:

[java]
view plain
copy

//1. 初始化  
viewpager = (ViewPager)this.findViewById(R.id.viewpager);  
adapter = new FragmentViewPagerAdapter(getSupportFragmentManager(), null);  
viewpager.setAdapter(adapter);  
//2. 加载数据  
List<String> urls = new ArrayList<String>();  
urls.add("http://172.16.28.253:8080/web/1.jsp");  
urls.add("http://172.16.28.253:8080/web/2.jsp");  
urls.add("http://172.16.28.253:8080/web/3.jsp");  
urls.add("http://172.16.28.253:8080/web/4.jsp");  
adapter.update(urls);  
//3. 做更新  
Button update = (Button) this.findViewById(R.id.update);  
update.setOnClickListener(new View.OnClickListener() {  
    @Override  
    public void onClick(View v) {  
        if(viewpager != null && adapter != null){  
            viewpager.setCurrentItem(3, true);  
            adapter.update(3);//重新加载position是3的页面  
        }  
    }  
});  

重构一下:

(1)BaseFragmentPagerAdapter.java

[java]
view plain
copy

public abstract class BaseFragmentPagerAdapter extends FragmentPagerAdapter{  
      
    private FragmentManager mFragmentManager;  
    private List<String> tagList = new ArrayList<String>();  
      
    public BaseFragmentPagerAdapter(FragmentManager fm) {  
        super(fm);  
        this.mFragmentManager = fm;  
    }  
      
    @Override  
    public Object instantiateItem(ViewGroup container, int position) {      
        tagList.add(makeFragmentName(container.getId(), getItemId(position)));      
        return super.instantiateItem(container, position);      
    }   
      
    @Override  
    public void destroyItem(ViewGroup container, int position, Object object){  
        super.destroyItem(container, position, object);  
        tagList.remove(makeFragmentName(container.getId(), getItemId(position)));  
    }  
      
    private static String makeFragmentName(int viewId, long id) {  
        return "android:switcher:" + viewId + ":" + id;  
    }  
      
    public void update(int position){  
        Fragment fragment = (Fragment)mFragmentManager.findFragmentByTag(tagList.get(position));    
        if(fragment == null){  
            return;  
        }  
        if(fragment instanceof UpdateAble){//这里唯一的要求是Fragment要实现UpdateAble接口  
            ((UpdateAble)fragment).update();  
        }  
    }  
      
    public interface UpdateAble {  
        public void update();  
    }  
}  

以后我们的Adapter只要继承BaseFragmentPagerAdapter就可以了,比如:
(2)FragmentViewPagerAdapter.java

[java]
view plain
copy

public class FragmentViewPagerAdapter extends BaseFragmentPagerAdapter {  
      
    private List<String> mDatas;  
  
    public FragmentViewPagerAdapter(FragmentManager fm, List<String> datas) {  
        super(fm);  
        this.mDatas = datas;  
    }  
  
    @Override  
    public Fragment getItem(int position) {  
        String url = mDatas.get(position);  
        WebViewFragmentV4 webview = new WebViewFragmentV4(url);  
        return webview;  
    }  
  
    @Override  
    public int getCount() {  
        if (mDatas == null) {  
            return 0;  
        } else {  
            return mDatas.size();  
        }  
    }  
  
    public void update(List<String> datas){  
        this.mDatas = datas;  
        notifyDataSetChanged();  
    }  
}  

跟普通的用法一样,唯一的要求是,Fragment必须要实现UpdateAble接口,perfect!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: