在一個 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);
}
}