8

我對FragmentPagerAdapter不熟悉,所以這將成爲我們(您)嚴格閱讀說明的那些問題之一。帶有ViewPager和兩個碎片的FragmentPagerAdapter。轉到第一個並更新第一個文本

結構:我有一個FragmentPagerAdapter(代碼如下),它將一次容納兩個片段。第一個顯示書籍摘錄,第二個顯示書名。

目標:我想達到的目標是在標題中描述:用戶可以導航到尋呼機的第二個片段,點擊標題,然後我想用戶移回第一片段和告訴第一個片段更新文本。第一個片段有一個triggerRefresh方法。

代碼:我相信我的問題發生,因爲FragmentPagerAdapter重用/創建片段(我不明白)的方式。這是我的課:

static class MyFragmentPagerAdapter extends FragmentPagerAdapter { 

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

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

    @Override 
    public Fragment getItem(int position) { 
     switch(position) { 
     case 0: 
      return new ExcerptsFragment(); 
     case 1: 
      return new BookListFragment(); 
     default: 
      throw new IllegalArgumentException("not this many fragments: " + position); 
     } 
    } 
} 

我這是怎麼產生的相關成員:

ViewPager mViewPager = (ViewPager) findViewById(R.id.pager); 
MyFragmentPagerAdapter mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager()); 
mViewPager.setAdapter(mFragmentPagerAdapter); 

而這就是我在我的活動其他地方試行,當我從書名收到回調片段與標題選擇:

mViewPager.setCurrentItem(0); // back to excerpts screen page. It's OK. 
// Here's the problem! How to identify the fragment 0 
// to ExcerptsFragment and call its triggerRefresh()?!? 

問題系列:

調用適配器的getView()將不起作用,因爲它將返回一個ExcerptsFragment的新實例,它不是當前附加的實例(如預期的那樣引發異常)。

我在這裏見過很多人(example)只是在getView()存儲片段。是對的嗎?因爲通過查看官方示例,對我來說看起來像是一種反模式(通過持有物品來擊敗自動引用)。這也是意見herehere(看起來對我來說)。

有什麼建議嗎?我不會感到驚訝,如果我不瞭解所有這一點...

回答

7

免責聲明:雖然這對我來說工作完全正常,你應該知道的經典缺陷取決於內部,私人行爲。雖然我寫測試最終會警告我內部實現是否發生了變化,但我後來轉向greener pastures。你也應該。因此,在我看來,這個問題的價值及其答案僅僅是歷史性的。


抱歉這個問題,我認爲這是小時。

爲了解決這個問題,我實現了this solution。似乎工作得很好。所以,我相信這只是找出(當前附加的)片段實例的問題,通過計算出它的Id是如何命名的。上面的鏈接解釋了它是如何製作的。

我選擇回答我自己的問題,而不是刪除它,因爲我相信這些傳呼機上像我這樣的新手會受益於「真實案例場景」。我所見過的大多數答案都是關於理論的,這是正確的方式,但是沒有一個真正的例子可以幫助像我這樣的人迷失方向。

無論如何,這裏是我需要(在評論上述部分),最後一塊代碼:

int n = 0; 
mViewPager.setCurrentItem(n); // in the question I had stopped here. 

ExcerptsFragment f = (ExcerptsFragment) ContainerActivity.this 
     .getSupportFragmentManager().findFragmentByTag(getFragmentTag(n)); 
f.triggerRefresh(); 

// ... below the helper method: used the solution from the link. 

private String getFragmentTag(int pos){ 
    return "android:switcher:"+R.id.pager+":"+pos; 
} 

所以,我有一種感覺,這是一個強大的解決方案,因爲我不是保留對碎片的任何引用(從而冒着引用過時的風險)。我至少保留自己的代碼,因此最大限度地減少了我做一些愚蠢的事情的機會。

當然,如果您有什麼要補充的,告訴我們,告訴我們做錯了什麼或者可以改進什麼,我很樂意聽到您的消息。

+0

您不應該依賴與分配標籤的內部機制的兼容性。看到我的答案類似的問題如何正確地做到這一點:http://stackoverflow.com/questions/14035090/how-to-get-existing-fragments-when-using-fragmentpageradapter/41345283#41345283 – morgwai 2016-12-27 13:37:54

+0

@morgwai謝謝你的警告我。我收錄了一份免責聲明,以警告潛在的讀者。 – davidcesarino 2016-12-27 19:50:22

+0

歡迎您:)我認爲最好是直接提供一個鏈接到我的答案(不僅僅是這個問題),因爲我的答案是非常新的,因此仍然得分很低,所以讀者可能會堅持2個頂部之一得分的答案,兩者都有問題。 (我爲我的答案添加了一些解釋,爲什麼重寫'instantiateItem'的解決方案本身可能不夠) – morgwai 2016-12-28 06:48:43

2

我一直在尋找解決這個問題的方法。原則上你的方法是可行的,但如果Android基類實現中的片段標籤創建代碼發生更改,它將會破壞你的代碼。這是一個相當骯髒的依賴!

更優雅的方法是解決問題並在基本片段中保留一個基本活動的實例。在您的活動中爲標記實現一個setter,並在創建時調用片段內部的標記 - getTag()僅提供標記。

可以找到一個示例實現here

+0

迄今爲止這個非常隨機的問題的最佳解決方案。但是有兩件事:你可以通過getActivity()獲得對「父活動」的引用。你需要記住,你需要通過配置更改來保持標籤名稱,因爲即使適配器可能被重新創建,這些片段可能不會(因此標籤不會再被設置) – jpm 2013-10-09 13:20:22

相關問題