2016-01-12 127 views
1

我想使用findFragmentById()得到一個片段引用,但它總是返回一個空對象。我已使用FragmentPagerAdapter並附加了OnPageChangeListener因此,無論何時滾動到特定片段(例如FragmentB),都應該觸發FragmentB的方法。SupportFragmentManager的findFragmentById總是返回null

我有以下代碼:

mPager.addOnPageChangeListener(new OnPageChangeListener() { 
    @Override 
    public void onPageSelected(int position) { 
     if (position == 1) { 
      FragmentB fb = (FragmentB) getSupportFragmentManager().findFragmentById(R.id.fragment_b); 

      fb.refreshList(); 
      //fb is always null 

      Toast.makeText(MainActivity.this,"Scrolled", Toast.LENGTH_SHORT).show();                   
      //Toast is working fine 
     } 
    } 

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

    @Override 
    public void onPageScrollStateChanged(int arg0){} 
}); 

回答

3

只是這樣做,而不是:

mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 
    @Override 
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 
     PagerAdapter pagerAdapter = (PagerAdapter) mPager.getAdapter(); 
     if (position == 1) { 
      FragmentB fragmentB = (FragmentB)pagerAdapter.getItem(position); 
      fragmentB.refreshList(); 
     } 
    } 

    @Override 
    public void onPageSelected(int position) {} 

    @Override 
    public void onPageScrollStateChanged(int state) {} 
}); 

findFragmentById的問題並不打算以這種方式被使用:

發現一個由給定ID標識的片段,當從XML充值時或者在事務中添加時作爲容器標識。這首先搜索當前添加到經理活動的片段;如果沒有找到這樣的片段,則搜索當前在與該ID相關聯的背堆棧中的所有片段。

您應該調用它以獲取片段容器中的哪個片段(例如,如果您正在使用Navigation Drawer並且想知道哪個片段位於視口中),而您正在使用ViewPager,它承載多個片段。

我希望它有幫助。

+0

謝謝。你的解決方案有效但是,你能告訴我是否想在MainActivity的onCreate()或onCreateView()中獲取'Fragment'嗎?我試過他們,但我總是得到一個NullPointerException。 – MrShadow

+0

@MrShadow你爲什麼要在'onCreate()'中調用fragment,即剛創建Adapter之後?它尚未附加到活動中。但無論如何,從適配器初始化後的類的幾乎任何一點你都可以這樣做:'((PagerAdapter)mPager.getAdapter())。getItem(mPager.getCurrentItem());' –

+0

我想添加一個自定義接口監聽片段以便片段可以相互通信。我在FragmentA中有一個recyclerview,在FragmentB中有另一個RecyclerView。我想在FragmentA中發生一些事情時更新FragmentB的RecyclerView。爲了實現這一點,我必須使用接口來實現分片間通信。這是我所指的[鏈接](http://stackoverflow.com/a/15448538/3561262) – MrShadow

2

findFragmentById()如果您沒有在活動的內容視圖(它是.xml文件)中聲明片段,將始終返回null,因爲您無法以編程方式設置片段的ID!

如果你有興趣,這裏是你的代碼可能看起來像一個活動的XML文件中的內容:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <fragment 
     android:id="@+id/my_id" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:name="com.mypackage.MyFragment"/> 
</LinearLayout> 

而這樣一來,查找在FragmentManagerfindFragmentById()片段會回報你的正確MyFragment的實例。

findFragmentById()是仰視的FragmentManager片段一個方式,但也有通過findFragmentByTag()另一個方式。

在你的情況,你最有可能通過以下方法設置這些片段在PagerAdapter的實例:

@Override 
public Fragment getItem(int position) {} 

現在有很多例子和答案鼓勵您使用一些反射得到來自FragmentManager的片段。 Android的自動生成一個標記爲每個片段,您可以用下面的方法來獲取此名稱:

private static String getFragmentName(int viewId, int id) { 
    return "android:switcher:" + viewId + ":" + id; 
} 

然後你就可以建立一個getter方法來得到這樣一個片段:

public Fragment getFragmentForPosition(int position) { 
    Fragment fragment = getSupportFragmentManager().findFragmentByTag(getFragmentName(mViewPager.getId(), getItemId(position))); 
    return fragment; // May be null if the fragment is not found. Handle that case too wherever you call this method. 
} 

viewId是來自ViewPager的xml文件的ID,並且id可以在具有getItemId(position)的任何地方的適配器中獲得。 這會起作用,但由於這裏使用了反射,所以它有點難以理解。

這是一個非常容易的,但醜陋的解決方案,如果Android團隊並沒有改變他們的邏輯中生成代碼:)這應該工作

請參考其他可能的解決方案列表中this SO響應。