2012-03-14 109 views
73

如何獲得在backstack中添加的最新片段實例(如果我不知道片段標籤& id)?在backstack中獲取最新的片段

FragmentManager fragManager = activity.getSupportFragmentManager(); 
FragmentTransaction fragTransacion = fragMgr.beginTransaction(); 

/****After add , replace fragments 
    (some of the fragments are add to backstack , some are not)***/ 

//HERE, How can I get the latest added fragment from backstack ?? 

回答

1

可以使用getBackStackEntryAt()。爲了知道你能有多少項活動在堆棧中擁有使用getBackStackEntryCount()

int lastFragmentCount = getBackStackEntryCount() - 1; 
+8

但是我怎樣才能得到最後一個片段在後臺? popBackStackEntryAt()只返回一個BackStackEntry實例,不是片段 – 2012-03-14 12:53:25

+0

是的,你是對的,但是每個BackStackEntry都存在,你可以通過getId()返回id。您可以使用此Id以檢索片段 – Blackbelt 2012-03-14 12:55:44

+1

獲取最後一個片段:getBackStackEntryCount() - 1 – 2013-04-08 09:12:18

119

您可以使用FragmentManager.BackStackEntrygetName()方法,該方法是在API級別14.此法出臺將返回這是一個標籤當你將片段添加到backstack中時使用的是addTobackStack(tag)

int index = getActivity().getFragmentManager().getBackStackEntryCount() - 1 
FragmentManager.BackStackEntry backEntry = getFragmentManager().getBackStackEntryAt(index); 
String tag = backEntry.getName(); 
Fragment fragment = getFragmentManager().findFragmentByTag(tag); 

你需要確保你添加的片段返回堆棧是這樣的:

fragmentTransaction.addToBackStack(tag); 
+0

這是有幫助的。無論最近哪個片段被添加到堆棧中,我們都可以通過名稱 – Braj 2013-07-19 08:38:41

+14

獲取堆棧中的任何片段,以便通過標記找到片段,它必須添加/替換爲相同的標記。 'FragmentTransaction.add(int containerViewId,Fragment fragment,String tag)'或'FragmentTransaction.replace(int containerViewId,Fragment fragment,String tag)' [doc](http://developer.android.com/reference/android /app/FragmentTransaction.html#replace(int,%20android.app.Fragment,%20java.lang.String)) – Saqib 2013-08-01 18:38:27

+1

這個問題是,如果你在後臺堆棧中有一個片段兩次,你不能檢索一個特定的當你擁有的只是索引或backstack入口實體時。 – Justin 2014-05-29 15:54:21

3

人Deepak戈埃爾給我不工作,因爲我總是從entry.getName()得到空的答案;

我做的是標籤設置爲片段是這樣的:

ft.add(R.id.fragment_container, fragmentIn, FRAGMENT_TAG); 

其中ft是我的片段交易,FRAGMENT_TAG是標籤。然後,我用這個代碼來獲取片段:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG); 
+0

只有當你給所有的片段使用同一個標籤時,這纔會起作用,如果你想在以後找到特定的片段,這不是一個好主意。 – Shirane85 2017-02-23 05:34:34

40
FragmentManager.findFragmentById(fragmentsContainerId) 

function鏈接返回到頂部在堆棧中Fragment。使用示例:

fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() { 
     @Override 
     public void onBackStackChanged() { 
      Fragment fr = fragmentManager.findFragmentById(R.id.fragmentsContainer); 
      if(fr!=null){ 
       Log.e("fragment=", fr.getClass().getSimpleName()); 
      } 
     } 
    }); 
+1

這個答案在我的項目中效果很好,因爲我將除根片段以外的每個片段添加到後端堆棧。但我想這個答案不會工作,如果最新添加的片段沒有添加到後臺堆棧中。 – 2014-08-15 08:15:15

2

保留您自己的背部堆疊:myBackStack。由於您的Add片段爲FragmentManager,因此也將其添加到myBackStack。當onBackStackChanged()myBackStack彈出時,其長度大於getBackStackEntryCount

0

或者您可以在添加與其內容相對應的片段時添加標籤並使用簡單的靜態字符串字段(也可以將其保存在onSaveInstanceState(Bundle)方法的活動實例包中)以保存最後添加的片段標籤並獲取此內容片段byTag()在你需要的任何時候......

26

我personnaly試過很多的解決方案,並結束了這個工作的解決方案:

添加將用於以下幾次去數這個實用方法你的後臺堆裏的碎片:

protected int getFragmentCount() { 
    return getSupportFragmentManager().getBackStackEntryCount(); 
} 

然後,當您使用FragmentTransaction方法添加/替換您的片段時,爲您的片段生成一個唯一標記(例如,:使用片段在你的籌碼數):

getSupportFragmentManager().beginTransaction().add(yourContainerId, yourFragment, Integer.toString(getFragmentCount())); 

最後,你可以用這個方法找到你的任何片段在堆棧中:

private Fragment getFragmentAt(int index) { 
    return getFragmentCount() > 0 ? getSupportFragmentManager().findFragmentByTag(Integer.toString(index)) : null; 
} 

因此,獲取在頂部片段您可以通過以下方式輕鬆實現後臺堆疊:

protected Fragment getCurrentFragment() { 
    return getFragmentAt(getFragmentCount() - 1); 
} 

希望能幫到你!

+0

這是我試過的最準確的解決方案 – mes 2016-03-25 13:13:19

6

fragmentMananger中有片段列表。請注意,刪除片段並不會使列表大小減少(片段條目只會變爲空)。因此,一個有效的解決辦法是:

public Fragment getTopFragment() { 
List<Fragment> fragentList = fragmentManager.getFragments(); 
Fragment top = null; 
    for (int i = fragentList.size() -1; i>=0 ; i--) { 
    top = (Fragment) fragentList.get(i); 
    if (top != null) { 
     return top; 
    } 
    } 
return top; 
} 
+0

這應該是選定的答案!非常感謝:) – 2016-02-04 23:45:36

+0

不可靠。原因有三:1)這是片段管理器知道的所有片段的列表,而不僅僅是堆棧中的那些片段。 2)不能保證片段管理器將在列表的最後添加新片段。當然,它會在簡單的測試中這樣做,但是如果一個片段被刪除,留下一個空值,那麼在某些情況下片段管理器決定重新使用該空的片段呢?不是說這樣做,但不能保證在任何情況下它永遠不會。 3)如果您或某個未來的程序員開始使用attach/detach來管理片段,這將不匹配堆棧。 – ToolmakerSteve 2016-09-20 11:45:24

1

其實有添加到堆棧,因爲你可以在一個事務中增加幾個或片段堆棧或只是刪除片段無需添加一個新的無最新片段。

如果你確實想要一堆碎片,並且能夠通過堆棧中的索引來訪問碎片,那麼最好在FragmentManager及其後臺上有一個抽象層。這裏是你如何能做到這一點:

public class FragmentStackManager { 
    private final FragmentManager fragmentManager; 
    private final int containerId; 

    private final List<Fragment> fragments = new ArrayList<>(); 

    public FragmentStackManager(final FragmentManager fragmentManager, 
     final int containerId) { 
    this.fragmentManager = fragmentManager; 
    this.containerId = containerId; 
    } 

    public Parcelable saveState() { 
    final Bundle state = new Bundle(fragments.size()); 
    for (int i = 0, count = fragments.size(); i < count; ++i) { 
     fragmentManager.putFragment(state, Integer.toString(i), fragments.get(i)); 
    } 
    return state; 
    } 

    public void restoreState(final Parcelable state) { 
    if (state instanceof Bundle) { 
     final Bundle bundle = (Bundle) state; 
     int index = 0; 
     while (true) { 
     final Fragment fragment = 
      fragmentManager.getFragment(bundle, Integer.toString(index)); 
     if (fragment == null) { 
      break; 
     } 

     fragments.add(fragment); 
     index += 1; 
     } 
    } 
    } 

    public void replace(final Fragment fragment) { 
    fragmentManager.popBackStackImmediate(
     null, FragmentManager.POP_BACK_STACK_INCLUSIVE); 
    fragmentManager.beginTransaction() 
     .replace(containerId, fragment) 
     .addToBackStack(null) 
     .commit(); 
    fragmentManager.executePendingTransactions(); 

    fragments.clear(); 
    fragments.add(fragment); 
    } 

    public void push(final Fragment fragment) { 
    fragmentManager 
     .beginTransaction() 
     .replace(containerId, fragment) 
     .addToBackStack(null) 
     .commit(); 
    fragmentManager.executePendingTransactions(); 

    fragments.add(fragment); 
    } 

    public boolean pop() { 
    if (isEmpty()) { 
     return false; 
    } 

    fragmentManager.popBackStackImmediate(); 

    fragments.remove(fragments.size() - 1); 
    return true; 
    } 

    public boolean isEmpty() { 
    return fragments.isEmpty(); 
    } 

    public int size() { 
    return fragments.size(); 
    } 

    public Fragment getFragment(final int index) { 
    return fragments.get(index); 
    } 
} 

現在不是增加並通過直接調用FragmentManager除去碎片,你應該使用的FragmentStackManagerpush()replace()pop()方法。您只需撥打stack.get(stack.size() - 1)即可訪問最上面的片段。

但是,如果你喜歡黑客,我不得不採取其他方式做類似的事情。我必須提到的唯一事情就是這些黑客只會在支持碎片的情況下才能使用。

第一個破解就是將所有活動片段添加到片段管理器中。如果你只是更換片段逐個彈出從堆棧此方法將返回最上面的片段:

public class BackStackHelper { 
    public static List<Fragment> getTopFragments(
     final FragmentManager fragmentManager) { 
    final List<Fragment> fragments = fragmentManager.getFragments(); 
    final List<Fragment> topFragments = new ArrayList<>(); 

    for (final Fragment fragment : fragments) { 
     if (fragment != null && fragment.isResumed()) { 
     topFragments.add(fragment); 
     } 
    } 

    return topFragments; 
    } 
} 

第二種方法是事件的詳細哈克,並允許您在最後交易得到補充的所有片段的這addToBackStack被稱爲:

package android.support.v4.app; 

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

public class BackStackHelper { 
    public static List<Fragment> getTopFragments(
     final FragmentManager fragmentManager) { 
    if (fragmentManager.getBackStackEntryCount() == 0) { 
     return Collections.emptyList(); 
    } 

    final List<Fragment> fragments = new ArrayList<>(); 

    final int count = fragmentManager.getBackStackEntryCount(); 
    final BackStackRecord record = 
     (BackStackRecord) fragmentManager.getBackStackEntryAt(count - 1); 
    BackStackRecord.Op op = record.mHead; 
    while (op != null) { 
     switch (op.cmd) { 
     case BackStackRecord.OP_ADD: 
     case BackStackRecord.OP_REPLACE: 
     case BackStackRecord.OP_SHOW: 
     case BackStackRecord.OP_ATTACH: 
      fragments.add(op.fragment); 
     } 
     op = op.next; 
    } 

    return fragments; 
    } 
} 

請注意,在這種情況下,你必須把這個類轉換android.support.v4.app包。

0

最高的(Deepak Goel)答案對我來說效果不好。不知何故標籤沒有被正確添加。

我最終只是通過流發送片段的ID(使用intents)並直接從片段管理器中檢索它。

1

這個輔助方法從堆棧的頂部得到片段:

public Fragment getTopFragment() { 
if (getSupportFragmentManager().getBackStackEntryCount() == 0) { 
    return null; 
} 
String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName(); 
return getSupportFragmentManager().findFragmentByTag(fragmentTag); 

}

+0

謝謝。最優雅的答案。爲Kotlin愛好者添加它https://stackoverflow.com/a/47336504/1761406 – Shirane85 2017-11-16 18:14:58

1

剛接手@roghayeh侯賽尼(正確)的答案,在科特林在2017年:)

使它成爲那些在這裏
fun getTopFragment(): Fragment? { 
    supportFragmentManager.run { 
     return when (backStackEntryCount) { 
      0 -> null 
      else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name) 
     } 
    } 
} 

*這應該從Activity中調用。

享受:)