รับชิ้นส่วนล่าสุดใน backstack


106

ฉันจะเพิ่มอินสแตนซ์แฟรกเมนต์ล่าสุดในแบ็คสแต็กได้อย่างไร (หากฉันไม่รู้จักแฟรกเมนต์แท็ก & id)

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 ??

คำตอบ:


156

คุณสามารถใช้getName()วิธีการFragmentManager.BackStackEntryที่เป็นที่รู้จักในระดับ 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);

24
ในการค้นหาแฟรกเมนต์โดยแท็กจะต้องเพิ่ม / แทนที่ด้วยแท็กเดียวกัน FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)หรือ FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) doc
Saqib

3
ปัญหานี้คือถ้าคุณมีแฟรกเมนต์ในแบ็คสแต็กสองครั้งคุณจะไม่สามารถดึงแฟรกเมนต์เฉพาะได้เมื่อสิ่งที่คุณมีคือดัชนีหรือเอนทิตีแบ็คสแต็ก
จัสติน

14
อะไรคือจุดที่เรียกมันstackว่าถ้าฉันไม่สามารถเข้าถึงแฟรกเมนต์ผ่านวิธีป๊อปได้?
Kenny Worden


1
ฉันไม่รู้ว่าทำไม แต่ findFragmentByTag กลับเป็นโมฆะแม้ว่าดีบั๊กจะแสดงให้เห็นอย่างชัดเจนว่าแท็กนั้นใช้ได้
htafoya

49
FragmentManager.findFragmentById(fragmentsContainerId) 

ฟังก์ชันส่งกลับลิงค์ไปด้านบน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());
            }
        }
    });

2
คำตอบนี้ใช้ได้ดีในโปรเจ็กต์ของฉันเนื่องจากฉันเพิ่มทุกส่วนยกเว้นส่วนของรูทลงในสแต็กด้านหลัง แต่ฉันเดาว่าคำตอบนี้จะใช้ไม่ได้หากไม่ได้เพิ่มส่วนที่เพิ่มล่าสุดลงในแบ็คสแต็ค
Arne Evertsson

41

ฉันลองใช้วิธีแก้ปัญหาเหล่านั้นหลายวิธีแล้วและลงเอยด้วยวิธีการทำงานนี้:

เพิ่มวิธียูทิลิตี้นี้ซึ่งจะใช้หลายครั้งด้านล่างเพื่อรับจำนวนชิ้นส่วนในแบ็คสแต็คของคุณ:

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);
}

หวังว่านี่จะช่วยได้!


10

วิธีการช่วยเหลือนี้รับส่วนจากด้านบนของสแต็ก:

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

1
ขอบคุณ. คำตอบที่สวยหรูที่สุด เพิ่มไว้ที่นี่สำหรับคนรัก Kotlin stackoverflow.com/a/47336504/1761406
Shirane85


6

มีรายการของชิ้นส่วนใน fragmentMananger โปรดทราบว่าการลบส่วนย่อยไม่ได้ทำให้ขนาดรายการลดลง (รายการส่วนย่อยเปลี่ยนเป็น null) ดังนั้นวิธีแก้ปัญหาที่ถูกต้องคือ:

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;
}

2
ไม่น่าเชื่อถือ. เหตุผลสามประการ: 1) นี่คือรายการของส่วนย่อยทั้งหมดที่ตัวจัดการส่วนย่อยรู้ไม่ใช่เฉพาะในสแต็ก 2) ไม่มีการรับประกันว่าตัวจัดการส่วนจะเพิ่มคนใหม่ต่อไปที่ท้ายรายการ แน่นอนว่าจะทำเช่นนั้นในการทดสอบอย่างง่าย แต่จะเกิดอะไรขึ้นถ้าส่วนหนึ่งถูกลบออกโดยปล่อยให้เป็นโมฆะจากนั้นภายใต้สถานการณ์บางอย่างตัวจัดการส่วนจะตัดสินใจที่จะใช้ช่องว่างนั้นซ้ำ ไม่ได้บอกว่าทำ แต่ไม่มีการรับประกันว่าจะไม่ทำไม่ว่าในสถานการณ์ใด ๆ 3) หากคุณหรือโปรแกรมเมอร์ในอนาคตเริ่มใช้ไฟล์แนบ / ถอดเพื่อจัดการชิ้นส่วนสิ่งนี้จะไม่ตรงกับสแต็ก
ToolmakerSteve

สวัสดีขอบคุณสำหรับวิธีแก้ปัญหาของคุณ แต่มันไม่สวยงามและง่าย
มูฮัมหมัดอาลี

ฉันสงสัยว่ามันเป็น Solutuin ที่ใช้งานได้ getFragments()ส่งคืนคอลเล็กชันชิ้นส่วนที่สั้นลง คนสุดท้ายอาจมองเห็นได้ แต่ไม่มากนัก
CoolMind

5

คำตอบที่ได้รับจาก goel Deepak ไม่ทำงานสำหรับฉันเพราะฉันมักจะได้รับจาก null entry.getName();

สิ่งที่ฉันทำคือตั้งแท็กเป็นส่วนย่อยด้วยวิธีนี้:

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

ft คือธุรกรรมส่วนย่อยของฉันและFRAGMENT_TAGเป็นแท็ก จากนั้นฉันใช้รหัสนี้เพื่อรับส่วน:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);

สิ่งนี้จะใช้ได้ผลก็ต่อเมื่อคุณให้ส่วนย่อยทั้งหมดเป็นแท็กเดียวกันซึ่งไม่ใช่ความคิดที่ดีหากคุณต้องการค้นหาส่วนเฉพาะในภายหลัง
Shirane85

4

เพิ่งใช้คำตอบ @roghayeh hosseini (ถูกต้อง) และทำใน Kotlin สำหรับผู้ที่อยู่ที่นี่ในปี 2560 :)

fun getTopFragment(): Fragment? {
    supportFragmentManager.run {
        return when (backStackEntryCount) {
            0 -> null
            else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name)
        }
    }
}

* สิ่งนี้ควรถูกเรียกจากภายในกิจกรรม

สนุก :)


3

คุณสามารถใช้getBackStackEntryAt () เพื่อให้ทราบจำนวนรายการที่กิจกรรมในแบ็คสแต็กคุณสามารถใช้getBackStackEntryCount ()

int lastFragmentCount = getBackStackEntryCount() - 1;

11
แต่ฉันจะได้รับชิ้นส่วนสุดท้ายในกองหลังได้อย่างไร ?? popBackStackEntryAt () ส่งคืนอินสแตนซ์ BackStackEntry เท่านั้นไม่ใช่
แฟรกเมนต์

ใช่คุณพูดถูก แต่ BackStackEntry ทุกตัวจะมีและ id ซึ่งคุณสามารถเรียกคืนได้ด้วย getId () คุณสามารถใช้รหัสนี้เพื่อดึงชิ้นส่วน
Blackbelt

1
ในการรับส่วนสุดท้าย: getBackStackEntryCount () - 1
An-droid

3
คำตอบนี้ไม่ถูกต้องฉันเห็นว่ารายการ backstack มี id เป็น 0 ดังนั้นจึงไม่สามารถเรียกส่วนย่อยด้วย id ได้
จัสติน

1
นี่เป็นเรื่องเก่า แต่สำหรับใครก็ตามที่เดินที่นี่ back stack ไม่ได้เก็บเศษชิ้นส่วน แต่เป็นธุรกรรมที่แยกส่วนนั่นเป็นสาเหตุที่คำตอบนี้ผิด
maciekjanusz

3

ฉันจะเพิ่มบางอย่างในคำตอบของ Deepak Goelเนื่องจากมีคนจำนวนมากที่ฉันรวมอยู่ด้วยได้รับค่าว่างโดยใช้วิธีการของเขา เห็นได้ชัดว่าจะทำให้แท็กทำงานได้เมื่อคุณเพิ่มส่วนในแบ็คสแต็คคุณควรทำเช่นนี้:

getSupportFragmentManager.beginTransaction().replace(R.id.container_id,FragmentName,TAG_NAME).addToBackStack(TAG_NAME).commit();

คุณต้องเพิ่มแท็กเดียวกันสองครั้ง

ฉันจะแสดงความคิดเห็น แต่ฉันไม่มี 50 ชื่อเสียง


คุณได้ 50 แล้ว :)
davidbilla

2

เก็บกองหลังของคุณเอง: myBackStack. ในขณะที่คุณAddเป็นส่วนหนึ่งของชิ้นส่วนให้FragmentManagerเพิ่มเข้าไปmyBackStackด้วย ในonBackStackChanged()ป๊อปจากเมื่อความยาวของมันมีค่ามากกว่าmyBackStackgetBackStackEntryCount


2

ดูเหมือนว่าจะมีบางอย่างเปลี่ยนไปในทางที่ดีขึ้นเนื่องจากโค้ดด้านล่างทำงานได้ดีสำหรับฉัน แต่ฉันไม่พบในคำตอบที่ให้ไว้แล้ว

Kotlin:

supportFragmentManager.fragments[supportFragmentManager.fragments.size - 1]

Java:

getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)

2

หากคุณใช้addToBackStack()คุณสามารถใช้รหัสต่อไปนี้

List<Fragment> fragments = fragmentManager.getFragments(); activeFragment = fragments.get(fragments.size() - 1);


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โดยตรงคุณควรใช้push(), replace()และวิธีการของpop() FragmentStackManagerและคุณจะสามารถเข้าถึงส่วนบนสุดได้เพียงแค่โทร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

หรือคุณอาจเพิ่มแท็กเมื่อเพิ่มแฟรกเมนต์ที่สอดคล้องกับเนื้อหาของพวกเขาและใช้ฟิลด์สตริงแบบคงที่แบบง่าย (คุณสามารถบันทึกไว้ในบันเดิลอินสแตนซ์กิจกรรมในเมธอด onSaveInstanceState (Bundle) เพื่อเก็บแท็กแฟรกเมนต์ที่เพิ่มล่าสุดและรับแฟรกเมนต์นี้ byTag () ทุกเวลาที่คุณต้องการ ...


0

คำตอบสูงสุด (Deepak Goel) ไม่ได้ผลสำหรับฉัน เพิ่มแท็กไม่ถูกต้อง

ฉันลงเอยด้วยการส่ง ID ของแฟรกเมนต์ผ่านโฟลว์ (โดยใช้ Intents) และดึงข้อมูลโดยตรงจากตัวจัดการแฟรกเมนต์


0

นักพัฒนา Kotlinสามารถใช้สิ่งนี้เพื่อรับส่วนปัจจุบัน:

        supportFragmentManager.addOnBackStackChangedListener {
        val myFragment = supportFragmentManager.fragments.last()

        if (null != myFragment && myFragment is HomeFragment) {
            //HomeFragment is visible or currently loaded
        } else {
            //your code
        }
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.