在viewpager中获取当前Fragment实例

下面是我的代码,其中3 Fragment classes每个嵌入到ViewPager上的3个选项卡中。我有菜单选项。如onOptionsItemSelected()中所示,通过选择一个选项,我需要更新当前可见的片段。要更新,我必须调用一个方法,这是在片段类。有人能建议一下如何调用这个方法吗?

public class MainActivity  extends ActionBarActivity {


ViewPager ViewPager;
TabsAdapter TabsAdapter;


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


ViewPager = new ViewPager(this);
ViewPager.setId(R.id.pager);
setContentView(ViewPager);


final ActionBar bar = getSupportActionBar();


bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);


//Attaching the Tabs to the fragment classes and setting the tab title.
TabsAdapter = new TabsAdapter(this, ViewPager);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass1"),
FragmentClass1.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass2"),
FragmentClass2.class, null);
TabsAdapter.addTab(bar.newTab().setText("FragmentClass3"),
FragmentClass3.class, null);




if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}


}


@Override
public boolean onOptionsItemSelected(MenuItem item) {


switch (item.getItemId()) {


case R.id.addText:


**// Here I need to call the method which exists in the currently visible Fragment class**


return true;


}


return super.onOptionsItemSelected(item);
}




@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getSupportActionBar().getSelectedNavigationIndex());


}


public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {


private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();


static final class TabInfo {
private final Class<?> clss;
private final Bundle args;


TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}


public TabsAdapter(ActionBarActivity activity, ViewPager pager) {
super(activity.getSupportFragmentManager());
mContext = activity;
mActionBar = activity.getSupportActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}


public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();


}


@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub


}


@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub


}


@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
mActionBar.setSelectedNavigationItem(position);
}


@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub


}


@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);


}
}


tabPosition = tab.getPosition();
}


@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub


}


@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}


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


}


}

假设下面是我想调用的方法updateList()的片段类:

 public class FragmentClass1{


ArrayList<String> originalData;




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


View fragmentView = inflater.inflate(R.layout.frag1, container, false);


originalData = getOriginalDataFromDB();


return fragmentView;


}




public void updateList(String text)
{
originalData.add(text);
//Here I could do other UI part that need to added
}
}
256588 次浏览

首先,跟踪所有“活动”片段页。在这种情况下,你在FragmentStatePagerAdapter中跟踪片段页,它被ViewPager使用。

@Override
public Fragment getItem(int index) {
Fragment myFragment = MyFragment.newInstance();
mPageReferenceMap.put(index, myFragment);
return myFragment;
}

为了避免保留对“非活动”片段页的引用,你需要实现FragmentStatePagerAdapter的destroyItem(…)方法:

@Override
public void destroyItem (ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mPageReferenceMap.remove(position);
}

当你需要访问当前可见的页面时,你可以调用:

int index = mViewPager.getCurrentItem();
MyAdapter adapter = ((MyAdapter)mViewPager.getAdapter());
MyFragment fragment = adapter.getFragment(index);

其中MyAdapter的getFragment(int)方法是这样的:

public MyFragment getFragment(int key) {
return mPageReferenceMap.get(key);
}

希望能有所帮助!

通过选择一个选项,我需要更新片段 目前可见的。< / p >

一个简单的方法是使用与FragmentPagerAdapter实现相关的技巧:

case R.id.addText:
Fragment page = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + ViewPager.getCurrentItem());
// based on the current position you can then cast the page to the correct
// class and call the method:
if (ViewPager.getCurrentItem() == 0 && page != null) {
((FragmentClass1)page).updateList("new item");
}
return true;

请重新考虑你的变量命名约定,使用类名作为变量名是非常令人困惑的(所以没有ViewPager ViewPager,使用ViewPager mPager为例)。

这是唯一的方法,我不得到NullPointerException实例变量的特定片段类。这可能对那些困在同一件事情上的人有帮助。在onOptionsItemSelected()中,我以如下方式编码:

if(viewPager.getCurrentItem() == 0) {
FragmentClass1 frag1 = (FragmentClass1)viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
frag1.updateList(text);
} else if(viewPager.getCurrentItem() == 1) {
FragmentClass2 frag2 = (FragRecentApps)viewPager
.getAdapter()
.instantiateItem(viewPager, viewPager.getCurrentItem());
frag2.updateList(text);
}
    public class MyPagerAdapter extends FragmentPagerAdapter {
private Fragment mCurrentFragment;


public Fragment getCurrentFragment() {
return mCurrentFragment;
}
//...
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (getCurrentFragment() != object) {
mCurrentFragment = ((Fragment) object);
}
super.setPrimaryItem(container, position, object);
}
}

我使用了以下方法:

 int index = vpPager.getCurrentItem();
MyPagerAdapter adapter = ((MyPagerAdapter)vpPager.getAdapter());
MyFragment suraVersesFragment = (MyFragment)adapter.getRegisteredFragment(index);

在我的活动中,我有:

int currentPage = 0;//start at the first tab
private SparseArray<Fragment> fragments;//list off fragments
viewPager.setOnPageChangeListener(new OnPageChangeListener() {


@Override
public void onPageSelected(int pos) {
currentPage = pos;//update current page
}


@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageScrollStateChanged(int arg0) {}
});






@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if(fragment instanceof Fragment1)
fragments.put(0, fragment);
if(fragment instanceof Fragment2)
fragments.put(2, fragment);
if(fragment instanceof Fragment3)
fragments.put(3, fragment);
if(fragment instanceof Fragment4)
fragments.put(4, fragment);
}


Then I have the following method for getting the current fragment


public Fragment getCurrentFragment() {
return fragments.get(currentPage);
}

这里有很多答案并没有真正解决这个基本事实,即真的没有办法可以预测地做到这一点,并且在某种程度上不会导致你在未来的某个时候搬起石头砸自己的脚。

FragmentStatePagerAdapter是唯一一个知道如何可靠地访问由FragmentManager跟踪的片段的类——任何试图猜测片段的id或标签的尝试都是不可靠的,长期的。当保存/恢复状态时,尝试手动跟踪实例可能无法正常工作,因为FragmentStatePagerAdapter在恢复状态时很可能不会调用回调。

我唯一能做的事情是复制FragmentStatePagerAdapter的代码,并添加一个方法,返回给定位置(mFragments.get(pos))的片段。注意,这个方法假设片段是实际可用的(例如,它在某个点是可见的)。

如果你特别喜欢冒险,你可以使用反射来访问私有mFragments列表的元素,但这样我们就回到了起点(列表的名称不能保证保持不变)。

我有同样的问题,并解决它使用这段代码。

MyFragment fragment = (MyFragment) thisActivity.getFragmentManager().findFragmentById(R.id.container);

只需将MyFragment的名称替换为片段的名称,并添加片段容器的id。

当前片段:

如果你用fragments标签栏模板创建了一个项目,这是有效的。

Fragment f = mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());

注意,这适用于默认的选项卡活动模板实现。

这比公认的答案更经得起未来的考验:

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {


/* ------------------------------------------------------------------------------------------ */
// region Private attributes :


private Context _context;
private FragmentManager _fragmentManager;
private Map<Integer, String> _fragmentsTags = new HashMap<>();


// endregion
/* ------------------------------------------------------------------------------------------ */






/* ------------------------------------------------------------------------------------------ */
// region Constructor :


public MyFragmentPagerAdapter(Context context, FragmentManager fragmentManager) {


super(fragmentManager);


_context = context;
_fragmentManager = fragmentManager;
}


// endregion
/* ------------------------------------------------------------------------------------------ */






/* ------------------------------------------------------------------------------------------ */
// region FragmentPagerAdapter methods :


@Override
public int getCount() { return 2; }


@Override
public Fragment getItem(int position) {


if(_fragmentsTags.containsKey(position)) {


return _fragmentManager.findFragmentByTag(_fragmentsTags.get(position));
}
else {


switch (position) {


case 0 : { return Fragment.instantiate(_context, Tab1Fragment.class.getName()); }
case 1 : { return Fragment.instantiate(_context, Tab2Fragment.class.getName()); }
}
}


return null;
}


@Override
public Object instantiateItem(ViewGroup container, int position) {


// Instantiate the fragment and get its tag :
Fragment result = (Fragment) super.instantiateItem(container, position);
_fragmentsTags.put(position, result.getTag());


return result;
}


// endregion
/* ------------------------------------------------------------------------------------------ */
}

如果每个Fragment添加自己的菜单项并直接处理onOptionsItemSelected(),就像官方文档中描述的那样,更好地解决这个问题。最好避免使用未记录的技巧。

通过选择一个选项,我需要更新当前可见的片段。

为了获得当前可见片段的引用,假设你有一个ViewPager的引用作为mPager。然后按照以下步骤将获得currentFragment的引用:

  1. PageAdapter adapter = mPager.getAdapter();
  2. int fragmentIndex = mPager.getCurrentItem();
  3. FragmentStatePagerAdapter fspa = (FragmentStatePagerAdapter)adapter;
  4. Fragment currentFragment = fspa.getItem(fragmentIndex);

第3行使用的唯一强制转换通常是有效的。FragmentStatePagerAdapter是ViewPager的一个有用的适配器。

重写FragmentPagerAdapter中的setPrimaryItem:该对象是可见的片段:

 @Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
if (mCurrentFragment != object) {
mCurrentFragment = (LeggiCapitoloFragment) object;
}
super.setPrimaryItem(container, position, object);
}

在阅读了所有的评论和答案之后,我将解释这个问题的最佳解决方案。最好的选择是@rik的解决方案,所以我的改进是基于他的。

而不是问每个FragmentClass喜欢

if(FragmentClass1){
...
if(FragmentClass2){
...
}

创建你自己的接口,让你的子片段实现它,就像这样

public interface MyChildFragment {
void updateView(int position);
}

然后,您可以启动和更新您的内部片段

Fragment childFragment = (Fragment) mViewPagerDetailsAdapter.instantiateItem(mViewPager,mViewPager.getCurrentItem());


if (childFragment != null) {
((MyChildFragment) childFragment).updateView();
}

注:注意你把代码放在哪里,如果你在系统实际创建它之前调用insatiateItem,那么你的子片段的savedInstanceState将为空

public void onCreate(@Nullable Bundle savedInstanceState){
super(savedInstanceState)
}

会使你的应用程序崩溃。

祝你好运

只需从寻呼机获取当前项,然后请求适配器到该位置的片段。

 int currentItem = viewPager.getCurrentItem();
Fragment item = mPagerAdapter.getItem(currentItem);
if (null != item && item.isVisible()) {
//do whatever want to do with fragment after doing type checking
return;
}

我知道已经太迟了,但我有一些非常简单的方法,

//在0位置的片段

((mFragment) viewPager.getAdapter().instantiateItem(viewPager, 0)).yourMethod();

获取当前片段-获取ViewPager中的位置pageselected上的公共无效(最终int位置),然后

public PlaceholderFragment getFragmentByPosition(Integer pos){
for(Fragment f:getChildFragmentManager().getFragments()){
if(f.getId()==R.viewpager && f.getArguments().getInt("SECTNUM") - 1 == pos) {
return (PlaceholderFragment) f;
}
}
return null;
}

SECTNUM -在Fragment的(int sectionNumber);中分配的位置参数

getChildFragmentManager()或getFragmentManager() -取决于如何创建SectionsPagerAdapter

FragmentStatePagerAdapter有一个名为instantiateItem的公共方法,它根据指定的参数值返回你的片段,这个方法有两个参数ViewGroup (ViewPager)和position。

public Object instantiateItem(ViewGroup container, int position);

使用该方法获取指定位置的片段,

Fragment fragment = (Fragment) adaper.instantiateItem(mViewPager, position);

FragmentStatePagerAdapter有一个名为mCurrentPrimaryItem的私有实例变量,类型为Fragment。人们不禁会想,为什么Android开发者不为它提供getter。此变量在setPrimaryItem()方法中实例化。因此,以这样一种方式重写这个方法,以便获得对这个变量的引用。我只是简单地声明了我自己的mCurrentPrimaryItem,并将setPrimaryItem()的内容复制到我的重写中。

在你的FragmentStatePagerAdapter的实现中:

private Fragment mCurrentPrimaryItem = null;


@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}


public TasksListFragment getCurrentFragment() {
return (YourFragment) mCurrentPrimaryItem;
}

你可以像这样定义PagerAdapter,然后你将能够在ViewPager中获得任何Fragment

private class PagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();


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


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


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


public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
}
}

来获取当前的Fragment

Fragment currentFragment = mPagerAdapter.getItem(mViewPager.getCurrentItem());
你可以在Fragment中实现一个BroadcastReceiver并发送 来自任何地方的意图。片段的接收器可以监听

.调用实例的方法 一个警告是要确保视图组件已经实例化 和(以及一些操作,如滚动列表,ListView)

这是最简单的方法:

fun getCurrentFragment(): Fragment? {
return if (count == 0) null
else instantiateItem(view_pager, view_pager.currentItem) as? Fragment
}

(芬兰湾的科特林代码)

只需调用instantiateItem(viewPager, viewPager.getCurrentItem()并将其转换为Fragment。你的项目已经被实例化了。为了确保您可以为getCount添加检查。

适用于FragmentPagerAdapterFragmentStatePagerAdapter!

当我们使用viewPager时,在activity中访问片段实例的一个好方法是instantiateItem(viewPager, index)。//index-你想要实例的片段的索引。

例如,我正在访问1索引的片段实例

Fragment fragment = (Fragment) viewPageradapter.instantiateItem(viewPager, 1);


if (fragment != null && fragment instanceof MyFragment) {
((MyFragment) fragment).callYourFunction();


}

如果你的寻呼机在一个片段中,那么使用这个:

private fun getPagerCurrentFragment(): Fragment? {
return childFragmentManager.findFragmentByTag("android:switcher:${R.id.myViewPagerId}:${myViewPager.currentItem}")
}

其中R.id.myViewPagerId是你的ViewPager在xml布局中的id。

根据他的回答@ chatat jain:

当我们使用viewPager时,在activity中访问片段实例的一个好方法是instantiateItem(viewPager, index)。//index-你想要实例的片段的索引。

如果你想在芬兰湾的科特林中这样做

val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
if ( fragment is YourFragmentFragment)
{
//DO somthign
}

0到0的片段实例

< p >//=========================================================================// //############################# 使用的例子 #################################// //=========================================================================//

这里有一个完整的例子,可以得到一个最迷失的愿景

这是我的。xml文件中的viewpager

   ...
<android.support.v4.view.ViewPager
android:id="@+id/mv_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"/>
...

和我插入标签的home活动

...
import kotlinx.android.synthetic.main.movie_tab.*


class HomeActivity : AppCompatActivity() {


lateinit var  adapter:HomeTabPagerAdapter


override fun onCreate(savedInstanceState: Bundle?) {
...
}






override fun onCreateOptionsMenu(menu: Menu) :Boolean{
...


mSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
...


override fun onQueryTextChange(newText: String): Boolean {


if (mv_viewpager.currentItem  ==0)
{
val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 0) as Fragment
if ( fragment is ListMoviesFragment)
fragment.onQueryTextChange(newText)
}
else
{
val fragment =  mv_viewpager.adapter!!.instantiateItem(mv_viewpager, 1) as Fragment
if ( fragment is ListShowFragment)
fragment.onQueryTextChange(newText)
}
return true
}
})
return super.onCreateOptionsMenu(menu)
}
...


}
getSupportFragmentManager().getFragments().get(viewPager.getCurrentItem());

将从上面一行检索到的实例转换为要处理的片段。工作得很好。

viewPager

是管理片段的寻呼机实例。

最好的方法是调用CallingFragmentName fragment = (CallingFragmentName) viewPager .getAdapter() .instantiateItem(viewPager, viewpage . getcurrentitem ());,它会重新实例化你所调用的Fragment,这样它就不会抛出空指针异常并调用该Fragment的任何方法。

在我之前的实现中,我存储了一列子片段,以便以后能够访问它们,但这是一个错误的实现,导致了巨大的内存泄漏。

我最终使用instantiateItem(...)方法来获取当前的Fragment:

val currentFragment = adapter?.instantiateItem(viewPager, viewPager.currentItem)

或者获取任何其他碎片位置:

val position = 0
val myFirstFragment: MyFragment? = (adapter?.instantiateItem(viewPager, position) as? MyFragment)

文档:

为给定位置创建页面。适配器负责 将视图添加到这里给出的容器中,尽管这是必须的 确保在返回时完成 finishUpdate (ViewGroup)。< / p >

你可以声明一个数组片段作为寄存器片段

class DashboardPagerAdapter(fm: FragmentManager?) : FragmentStatePagerAdapter(fm!!) {
// CURRENT FRAGMENT
val registeredFragments = SparseArray<Fragment>()


override fun instantiateItem(container: ViewGroup, position: Int): Any {
val fragment = super.instantiateItem(container, position) as Fragment
registeredFragments.put(position, fragment)
return fragment
}


override fun getItem(position: Int): Fragment {
return when (position) {
0 -> HomeFragment.newInstance()
1 -> ConverterDashboardFragment.newInstance()
2 -> CartFragment.newInstance()
3 -> CustomerSupportFragment.newInstance()
4 -> ProfileFragment.newInstance()
else -> ProfileFragment.newInstance()
}
}


override fun getCount(): Int {
return 5
}


}

然后你可以用它作为

adapter?.let {
val cartFragment = it.registeredFragments[2] as CartFragment?
cartFragment?.myCartApi(true)
}

我尝试了以下方法:

 int index = mViewPager.getCurrentItem();
List<Fragment> fragments = getSupportFragmentManager().getFragments();
View rootView = fragments.get(index).getView();

因为FragmentStateAdapter会在FragmentManager中添加新的Fragment,而不是在屏幕旋转时创建新的Fragment,所以你只需要在FragmentManager中获得良好的性能

public MyFragment getActiveFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
for (Fragment fragment : fragments){
if(fragment instanceof  MyFragment){
return (MyFragment) fragment;
}
}
return null;
}