Viewpager+fragment數據更新問題解析

在一個 Android 應用中,我們可以使用 FragmentPageAdapter

來處理多 Fragment 頁面的橫向滑動。但是當 Fragment 對應的數據集發生改變時,我們都希望能夠通過調用 mAdapter.notifyDataSetChanged() 來觸發 Fragment 頁面使用新的數據調整或重新生成其內容,可是當我們使用 notifyDataSetChanged() 後,我們會發現這個方法不會生效。那爲什麼會這樣呢,之前遇到了相同的問題一直沒法解決,在網上給出的亂七八糟的答案感覺也不是正解,終於在今早徹底解決了這個問題。我們先來了解下FragmentPagerAdapter的源代碼。

@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);  
    }  
    
    return fragment;  
  }

       我們特別關注下以下這句

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

     根據原代碼我們可以知道系統給每一個Fragment都打上了一個標籤,通過標籤來尋找相應的fragment,所以當我們第二次進入fragment的時候,fragment的oncreate,oncreateView方法都不會被調用的,因爲FragmentPageAdapter

中的getitem()方法根本不會被調用,因爲系統會根據標籤找到相應的fragment,如果已經存在,就不會被調用,fragment有一個緩存機制在這裏。那麼如果我們一定要更新fragment,那麼我們又該如何處理呢,我們就可以以其人之道,還治其人之身,我們可以通過tag標籤找到我們相應的fragment,就可以對該fragment進行更新。那麼我們現在就開始吧。

我們先來定義一個list<String> tagList 來存儲一下tag

private List<String> tagList;

    第二部

重寫instantiateItem

方法,把fragment對應的標籤存儲在taglist集合裏

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

         makeFragmentName()是

FragmentPageAdapter源碼裏打fragment標籤的方法

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

第三步我們再adapter裏自己寫一個update()方法

public void update(int item) {
      Fragment fragment = fm.findFragmentByTag(tagList.get(item));
      if (fragment != null) {
        switch (item) {
        case 0:

          break;
        case 1:
          ((QueryFragment) fragment).update();
          break;
        case 2:

          break;
        default:
          break;
        }
      }
    }

      我們可以發現在queryFragment裏也有一個update()方法,這個方法呢就是接下來我們用接口回掉機制更新我們相應fragment的要使用的方法,方法裏的內容根據自己的需要編譯就可以了。

好的現在萬事具備只要實現fragment的數據更新問題就可以了,通過接口回掉機制來實現。

首先我們定義一個接口,讓我們的主Activity來實現

public interface FragmentListener {  
      
        public void onFragmentClickListener(int item);  
    }

   之後比如我們在A Fragment 裏頭插入了數據,需要BFragment對該數據進行顯示,那麼我們現在AFragment的onAttach方法中

public void onAttach(Activity activity) {  
  super.onAttach(activity);  
  try {  
      listener = (FragmentListener)activity;  
  } catch (Exception e) {  
      e.printStackTrace();  
     
  }  
    }

    然後對數據更新的時候,我們就在Afragment調用這個接口

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

   然後我們回到Activity實現該接口裏的方法,更新BFragment界面

public void onFragmentClickListener(int item) {
    adapter.update(item);
    adapter.update(item);
  }

   大功告成了,貼一下完整的MainAcitivity代碼吧!

package com.example.account.main;

import java.util.ArrayList;

import java.util.List;

import com.example.account.add.AddFragment;
import com.example.account.query.QueryFragment;
import com.example.account.setting.SettingFragment;
import com.example.account.utils.PagerSlidingTabStrip;
import com.melhc.xiji.R;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.view.ViewPager;

import android.util.DisplayMetrics;

import android.util.TypedValue;

import android.view.KeyEvent;
import android.view.ViewGroup;
import android.widget.Toast;

public class MainActivity extends FragmentActivity implements FragmentListener{
  private MyPagerAdapter adapter;
  private AddFragment addFragment;
  private List<String> tagList;
  private SettingFragment settingFragment;
  private boolean isExit;
  private QueryFragment queryFragment;
  private ViewPager pager;
  private PagerSlidingTabStrip tabs;
  private FragmentManager fm;
  private DisplayMetrics dm;
  private List<Fragment> list;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    pager = (ViewPager) findViewById(R.id.pager);
    tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
    initFragment();
    fm = getSupportFragmentManager();
    tagList = new ArrayList<String>();
    adapter = new MyPagerAdapter(fm);
    pager.setAdapter(adapter);
    tabs.setViewPager(pager);
  
  }

  public void initFragment() {
    list = new ArrayList<Fragment>();
    addFragment = new AddFragment();
    queryFragment = new QueryFragment();
    settingFragment = new SettingFragment();
    list.add(addFragment);
    list.add(queryFragment);
    list.add(settingFragment);
  }



  public class MyPagerAdapter extends FragmentPagerAdapter {

    public MyPagerAdapter(FragmentManager fm) {

      super(fm);
    }

    private final String[] titles = { "1", "2", "3" };

    @Override
    public CharSequence getPageTitle(int position) {
      return titles[position];
    }

    @Override
    public int getCount() {
      return titles.length;
    }

    @Override
    public Fragment getItem(int position) {
      return list.get(position);
    }

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

    public void update(int item) {
      Fragment fragment = fm.findFragmentByTag(tagList.get(item));
      if (fragment != null) {
        switch (item) {
        case 0:

          break;
        case 1:
          ((QueryFragment) fragment).update();
          break;
        case 2:

          break;
        default:
          break;
        }
      }
    }

  }

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



  public void onFragmentClickListener(int item) {
    adapter.update(item);
    adapter.update(item);
  }
  

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章