首页 > 移动开发 > Viewpager+fragment数据更新问题解析

Viewpager+fragment数据更新问题解析

 在一个 Android 应用中,我们可以使用 FragmentPageAdapter 来处理多 Fragment 页面的横向滑动。但是当 Fragment 对应的数据集发生改变时,我们都希望能够通过调用 mAdapter.notifyDataSetChanged() 来触发 Fragment 页面使用新的数据调整或重新生成其内容,可是当我们使用 notifyDataSetChanged() 后,我们会发现这个方法不会生效。那为什么会这样呢,之前遇到了相同的问题一直没法解决,在网上给出的乱七八糟的答案感觉也不是正解,终于在今早彻底解决了这个问题。我们先来了解下FragmentPagerAdapter的源代码。

  1. @Override    
  2. public Object instantiateItem(ViewGroup container, int position) {    
  3.     if (mCurTransaction == null) {    
  4.         mCurTransaction = mFragmentManager.beginTransaction();    
  5.     }    
  6.     
  7.     final long itemId = getItemId(position);    
  8.     
  9.     // Do we already have this fragment?    
  10.     String name = makeFragmentName(container.getId(), itemId);    
  11.     Fragment fragment = mFragmentManager.findFragmentByTag(name);    
  12.     if (fragment != null) {    
  13.         if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);    
  14.         mCurTransaction.attach(fragment);    
  15.     } else {    
  16.         fragment = getItem(position);    
  17.         if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);    
  18.         mCurTransaction.add(container.getId(), fragment,    
  19.                 makeFragmentName(container.getId(), itemId));    
  20.     }    
  21.     if (fragment != mCurrentPrimaryItem) {    
  22.         fragment.setMenuVisibility(false);    
  23.         fragment.setUserVisibleHint(false);    
  24.     }    
  25.     
  26.     return fragment;    
  27. }    


       我们特别关注下以下这句

  1. String name = makeFragmentName(container.getId(), itemId);    
  2. Fragment fragment = mFragmentManager.findFragmentByTag(name);    


     根据原代码我们可以知道系统给每一个Fragment都打上了一个标签,通过标签来寻找相应的fragment,所以当我们第二次进入fragment的时候,fragment的oncreate,oncreateView方法都不会被调用的,因为FragmentPageAdapter中的getitem()方法根本不会被调用,因为系统会根据标签找到相应的fragment,如果已经存在,就不会被调用,fragment有一个缓存机制在这里。那么如果我们一定要更新fragment,那么我们又该如何处理呢,我们就可以以其人之道,还治其人之身,我们可以通过tag标签找到我们相应的fragment,就可以对该fragment进行更新。那么我们现在就开始吧。

    我们先来定义一个list<String> tagList 来存储一下tag

  1. private List<String> tagList;  

    第二部重写instantiateItem方法,把fragment对应的标签存储在taglist集合里

  1. public Object instantiateItem(ViewGroup container, int position) {    
  2.     tagList.add(makeFragmentName(container.getId(), getItemId(position)));    
  3.     return super.instantiateItem(container, position);    
  4. }    

         makeFragmentName()是FragmentPageAdapter源码里打fragment标签的方法

  1. public static String makeFragmentName(int viewId, int index) {  
  2.         return "android:switcher:" + viewId + ":" + index;  
  3.     }  

   第三步我们再adapter里自己写一个update()方法

  1. public void update(int item) {  
  2.         Fragment fragment = fm.findFragmentByTag(tagList.get(item));  
  3.         if (fragment != null) {  
  4.             switch (item) {  
  5.             case 0:  
  6.   
  7.                 break;  
  8.             case 1:  
  9.                 ((QueryFragment) fragment).update();  
  10.                 break;  
  11.             case 2:  
  12.   
  13.                 break;  
  14.             default:  
  15.                 break;  
  16.             }  
  17.         }  
  18.     }  


      我们可以发现在queryFragment里也有一个update()方法,这个方法呢就是接下来我们用接口回掉机制更新我们相应fragment的要使用的方法,方法里的内容根据自己的需要编译就可以了。

   好的现在万事具备只要实现fragment的数据更新问题就可以了,通过接口回掉机制来实现。

   

   首先我们定义一个接口,让我们的主Activity来实现

  1. public interface FragmentListener {    
  2.     
  3.     public void onFragmentClickListener(int item);    
  4. }    


   之后比如我们在A Fragment 里头插入了数据,需要BFragment对该数据进行显示,那么我们现在AFragment的onAttach方法中

  1. public void onAttach(Activity activity) {    
  2.     super.onAttach(activity);    
  3.     try {    
  4.         listener = (FragmentListener)activity;    
  5.     } catch (Exception e) {    
  6.         e.printStackTrace();    
  7.          
  8.     }    
  9. }    

    然后对数据更新的时候,我们就在Afragment调用这个接口

  1. if (listener != null) {  
  2.                             listener.onFragmentClickListener(1);  
  3.                         }  


   然后我们回到Activity实现该接口里的方法,更新BFragment界面

  1. public void onFragmentClickListener(int item) {  
  2.         adapter.update(item);  
  3.         adapter.update(item);  
  4.     }  


   大功告成了,贴一下完整的MainAcitivity代码吧!

  1. package com.example.account.main;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. import java.util.List;  
  6.   
  7. import com.example.account.add.AddFragment;  
  8. import com.example.account.query.QueryFragment;  
  9. import com.example.account.setting.SettingFragment;  
  10. import com.example.account.utils.PagerSlidingTabStrip;  
  11. import com.melhc.xiji.R;  
  12.   
  13. import android.annotation.SuppressLint;  
  14. import android.content.Intent;  
  15. import android.graphics.Color;  
  16. import android.os.Bundle;  
  17. import android.os.Handler;  
  18. import android.os.Message;  
  19. import android.support.v4.app.Fragment;  
  20. import android.support.v4.app.FragmentActivity;  
  21. import android.support.v4.app.FragmentManager;  
  22. import android.support.v4.app.FragmentPagerAdapter;  
  23.   
  24. import android.support.v4.view.ViewPager;  
  25.   
  26. import android.util.DisplayMetrics;  
  27.   
  28. import android.util.TypedValue;  
  29.   
  30. import android.view.KeyEvent;  
  31. import android.view.ViewGroup;  
  32. import android.widget.Toast;  
  33.   
  34. public class MainActivity extends FragmentActivity implements FragmentListener{  
  35.     private MyPagerAdapter adapter;  
  36.     private AddFragment addFragment;  
  37.     private List<String> tagList;  
  38.     private SettingFragment settingFragment;  
  39.     private boolean isExit;  
  40.     private QueryFragment queryFragment;  
  41.     private ViewPager pager;  
  42.     private PagerSlidingTabStrip tabs;  
  43.     private FragmentManager fm;  
  44.     private DisplayMetrics dm;  
  45.     private List<Fragment> list;  
  46.   
  47.     @Override  
  48.     protected void onCreate(Bundle savedInstanceState) {  
  49.         super.onCreate(savedInstanceState);  
  50.         setContentView(R.layout.activity_main);  
  51.         pager = (ViewPager) findViewById(R.id.pager);  
  52.         tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);  
  53.         initFragment();  
  54.         fm = getSupportFragmentManager();  
  55.         tagList = new ArrayList<String>();  
  56.         adapter = new MyPagerAdapter(fm);  
  57.         pager.setAdapter(adapter);  
  58.         tabs.setViewPager(pager);  
  59.       
  60.     }  
  61.   
  62.     public void initFragment() {  
  63.         list = new ArrayList<Fragment>();  
  64.         addFragment = new AddFragment();  
  65.         queryFragment = new QueryFragment();  
  66.         settingFragment = new SettingFragment();  
  67.         list.add(addFragment);  
  68.         list.add(queryFragment);  
  69.         list.add(settingFragment);  
  70.     }  
  71.   
  72.   
  73.   
  74.     public class MyPagerAdapter extends FragmentPagerAdapter {  
  75.   
  76.         public MyPagerAdapter(FragmentManager fm) {  
  77.   
  78.             super(fm);  
  79.         }  
  80.   
  81.         private final String[] titles = { "1""2""3" };  
  82.   
  83.         @Override  
  84.         public CharSequence getPageTitle(int position) {  
  85.             return titles[position];  
  86.         }  
  87.   
  88.         @Override  
  89.         public int getCount() {  
  90.             return titles.length;  
  91.         }  
  92.   
  93.         @Override  
  94.         public Fragment getItem(int position) {  
  95.             return list.get(position);  
  96.         }  
  97.   
  98.         public Object instantiateItem(ViewGroup container, int position) {  
  99.             tagList.add(makeFragmentName(container.getId(),  
  100.                     (int) getItemId(position)));  
  101.             return super.instantiateItem(container, position);  
  102.         }  
  103.   
  104.         public void update(int item) {  
  105.             Fragment fragment = fm.findFragmentByTag(tagList.get(item));  
  106.             if (fragment != null) {  
  107.                 switch (item) {  
  108.                 case 0:  
  109.   
  110.                     break;  
  111.                 case 1:  
  112.                     ((QueryFragment) fragment).update();  
  113.                     break;  
  114.                 case 2:  
  115.   
  116.                     break;  
  117.                 default:  
  118.                     break;  
  119.                 }  
  120.             }  
  121.         }  
  122.   
  123.     }  
  124.   
  125.     public static String makeFragmentName(int viewId, int index) {  
  126.         return "android:switcher:" + viewId + ":" + index;  
  127.     }  
  128.   
  129.   
  130.   
  131.     public void onFragmentClickListener(int item) {  
  132.         adapter.update(item);  
  133.         adapter.update(item);  
  134.     }  
  135.       
  136.   

本文固定链接: http://www.devba.com/index.php/archives/5826.html | 开发吧

Viewpager+fragment数据更新问题解析:目前有1 条留言

  1. 沙发
    Cindy:

    为什么update两次?

    2015-12-03 下午 11:26