nhận được đoạn mới nhất trong backstack


104

Làm cách nào để tôi có thể thêm phiên bản phân đoạn mới nhất vào backstack (nếu tôi không biết thẻ & id phân đoạn)?

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

Câu trả lời:


156

Bạn có thể sử dụng getName()phương thức FragmentManager.BackStackEntryđã được giới thiệu ở cấp độ API 14. Phương thức này sẽ trả về một thẻ mà bạn đã sử dụng khi thêm Fragment vào backstack addTobackStack(tag).

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

Bạn cần đảm bảo rằng bạn đã thêm phân đoạn vào backstack như sau:

fragmentTransaction.addToBackStack(tag);

24
để tìm phân đoạn theo thẻ, nó phải được thêm / thay thế bằng cùng một thẻ. FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)hoặc FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) doc
Saqib

3
Vấn đề với điều này là nếu bạn có một phân đoạn trong ngăn xếp phía sau hai lần, bạn không thể truy xuất một phân đoạn cụ thể khi tất cả những gì bạn có là chỉ mục hoặc thực thể backstackentry.
Justin

14
Gọi nó là stackgì nếu tôi không thể truy cập phân mảnh thông qua một phương thức pop?
Kenny Worden


1
Tôi không biết tại sao nhưng findFragmentByTag đang trả về giá trị rỗng, ngay cả khi trình gỡ lỗi hiển thị rõ ràng rằng thẻ vẫn ổn.
htafoya

49
FragmentManager.findFragmentById(fragmentsContainerId) 

hàm trả về liên kết lên đầu Fragmenttrong ngăn xếp. Ví dụ sử dụng:

    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
Câu trả lời này hoạt động tốt trong dự án của tôi vì tôi thêm mọi phân đoạn ngoại trừ phân đoạn gốc vào ngăn xếp phía sau. Nhưng tôi đoán câu trả lời này sẽ không hoạt động nếu đoạn được bổ sung mới nhất không được thêm vào backstack.
Arne Evertsson

40

Tôi đã thử nhiều giải pháp đó và kết thúc với giải pháp hiệu quả này:

Thêm phương thức tiện ích này sẽ được sử dụng nhiều lần bên dưới để lấy số lượng mảnh vỡ trong gói phụ của bạn:

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

Sau đó, khi bạn thêm / thay thế phân đoạn của mình bằng phương thức FragmentTransaction, hãy tạo một thẻ duy nhất cho phân đoạn của bạn (ví dụ: bằng cách sử dụng số lượng phân mảnh trong ngăn xếp của bạn):

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

Cuối cùng, bạn có thể tìm thấy bất kỳ mảnh vỡ nào của mình trong ngăn lưng bằng phương pháp này:

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

Do đó, bạn có thể dễ dàng tìm nạp phân đoạn trên cùng trong backstack của bạn bằng cách gọi:

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

Hi vọng điêu nay co ich!


10

phương thức trợ giúp này lấy phân đoạn từ đầu ngăn xếp:

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

1
Cảm ơn. Câu trả lời thanh lịch nhất. Thêm nó ở đây cho những người yêu Kotlin stackoverflow.com/a/47336504/1761406
Shirane85


6

Có một danh sách các đoạn tronggmentMananger. Lưu ý rằng việc loại bỏ một phân mảnh không làm cho kích thước danh sách giảm xuống (mục nhập phân mảnh chỉ chuyển thành null). Do đó, một giải pháp hợp lệ sẽ là:

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
Không đáng tin cậy. Ba lý do: 1) Đây là danh sách tất cả các phân mảnh mà trình quản lý phân mảnh biết, không chỉ những phân mảnh trên ngăn xếp. 2) Không có gì đảm bảo rằng trình quản lý phân mảnh sẽ tiếp tục thêm những cái mới vào cuối danh sách. Chắc chắn, nó sẽ làm như vậy trong các bài kiểm tra đơn giản, nhưng điều gì sẽ xảy ra nếu một phân đoạn bị loại bỏ, để lại giá trị rỗng và sau đó trong một số trường hợp, trình quản lý phân đoạn quyết định sử dụng lại vùng trống đó? Không nói là có, nhưng không có gì đảm bảo rằng nó sẽ không bao giờ xảy ra, trong bất kỳ hoàn cảnh nào. 3) Nếu bạn hoặc một số lập trình viên tương lai bắt đầu sử dụng đính kèm / tách rời để quản lý các phân đoạn, điều này sẽ không khớp với ngăn xếp.
Thợ làm công cụ:

Hi, nhờ giải pháp của bạn, nhưng nó không phải là đẹp và dễ dàng
Muhammad Ali

Tôi nghi ngờ nó là một solutuin hoạt động. getFragments()trả về một tập hợp các đoạn ngắn. Có thể người cuối cùng được nhìn thấy, nhưng không có nhiều người khác.
CoolMind

5

Câu trả lời được đưa ra bởi deepak goel không phù hợp với tôi vì tôi luôn nhận được từ null entry.getName();

Những gì tôi làm là đặt Thẻ cho phân đoạn theo cách này:

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

Nơi ft là giao dịch phân đoạn của tôi và FRAGMENT_TAGlà thẻ. Sau đó, tôi sử dụng mã này để lấy phân đoạn:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);

Điều này sẽ chỉ hoạt động nếu bạn cung cấp cho tất cả các phân đoạn cùng một thẻ, đây không phải là ý kiến ​​hay nếu bạn muốn tìm một phân đoạn cụ thể sau đó.
Shirane85 23/02/17

4

Chỉ cần lấy câu trả lời @roghayeh hosseini (đúng) và làm nó trong Kotlin cho những người ở đây vào năm 2017 :)

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

* Điều này sẽ được gọi từ bên trong một Hoạt động.

Thưởng thức :)


3

bạn có thể sử dụng getBackStackEntryAt () . Để biết hoạt động có bao nhiêu mục nhập trong backstack, bạn có thể sử dụng getBackStackEntryCount ()

int lastFragmentCount = getBackStackEntryCount() - 1;

11
Nhưng làm thế nào tôi có thể lấy mảnh cuối cùng trong backstack ?? Các popBackStackEntryAt () chỉ trả về một thể hiện BackStackEntry, KHÔNG mảnh
Leem.fin

vâng, bạn nói đúng, nhưng mọi BackStackEntry đều giữ và id mà bạn có thể truy xuất bằng getId (). bạn có thể sử dụng ID này để lấy mảnh
Blackbelt

1
Để lấy mảnh cuối cùng: getBackStackEntryCount () - 1
An-droid

3
Câu trả lời này sai, tôi thấy các mục nhập backstack có id là 0, vì vậy không thể truy xuất phân đoạn theo id.
Justin

1
Đây là cũ, nhưng đối với bất cứ ai mà lang thang ở đây: chồng lại không giữ mảnh vỡ, nhưng giao dịch đoạn, đó là lý do tại sao câu trả lời này là sai
maciekjanusz

3

Tôi sẽ thêm điều gì đó vào câu trả lời của Deepak Goel vì rất nhiều người, bao gồm cả tôi, đã nhận được vô hiệu bằng cách sử dụng phương pháp của anh ấy. Rõ ràng để làm cho thẻ hoạt động khi bạn thêm một phân đoạn vào backstack, bạn nên làm như thế này:

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

Bạn cần thêm cùng một thẻ hai lần.

Tôi sẽ nhận xét nhưng tôi không có 50 danh tiếng.


bây giờ bạn có 50 :)
davidbilla

2

Giữ chồng trở lại của riêng bạn: myBackStack. Khi bạn Addlà một phân đoạn FragmentManager, hãy thêm nó vào myBackStack. Trong onBackStackChanged()cửa sổ bật lên từ myBackStackkhi độ dài của nó lớn hơn getBackStackEntryCount.


2

Có vẻ như có điều gì đó đã thay đổi theo hướng tốt hơn, vì mã bên dưới hoạt động hoàn hảo đối với tôi, nhưng tôi không tìm thấy nó trong các câu trả lời đã được cung cấp.

Kotlin:

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

Java:

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

2

Nếu bạn sử dụng addToBackStack(), bạn có thể sử dụng mã sau.

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


1

Trên thực tế, không có phân đoạn mới nhất nào được thêm vào ngăn xếp vì bạn có thể thêm một số hoặc các phân đoạn vào ngăn xếp trong một giao dịch duy nhất hoặc chỉ xóa các phân đoạn mà không thêm một đoạn mới.

Nếu bạn thực sự muốn có một chồng các phân đoạn và để có thể truy cập một phân đoạn bằng chỉ mục của nó trong ngăn xếp, tốt hơn bạn nên có một lớp trừu tượng trên FragmentManagervà backstack của nó. Đây là cách bạn có thể làm điều đó:

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

Bây giờ thay vì thêm và loại bỏ các mảnh vỡ bằng cách gọi FragmentManagertrực tiếp, bạn nên sử dụng push(), replace()pop()phương pháp FragmentStackManager. Và bạn sẽ có thể truy cập phân đoạn trên cùng chỉ bằng cách gọi stack.get(stack.size() - 1).

Nhưng nếu bạn thích hack, tôi phải làm những cách khác tương tự. Điều duy nhất tôi phải đề cập là các bản hack này sẽ chỉ hoạt động với các mảnh hỗ trợ.

Lần hack đầu tiên chỉ là để thêm tất cả các phân mảnh đang hoạt động vào trình quản lý phân mảnh. Nếu bạn chỉ thay thế từng đoạn một và bật từ ngăn xếp, phương pháp này sẽ trả về đoạn trên cùng:

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

Cách tiếp cận thứ hai là sự kiện phức tạp hơn và cho phép bạn nhận được tất cả các phân đoạn được thêm vào trong giao dịch cuối cùng addToBackStackđược gọi là:

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

Xin lưu ý rằng trong trường hợp này, bạn phải đặt lớp này vào android.support.v4.appgói.


0

Hoặc bạn có thể chỉ thêm một thẻ khi thêm các đoạn tương ứng với nội dung của chúng và sử dụng trường Chuỗi tĩnh đơn giản (bạn cũng có thể lưu nó trong gói phiên bản hoạt động trong phương thức onSaveInstanceState (Bundle)) để giữ thẻ đoạn được thêm cuối cùng và lấy đoạn này byTag () bất cứ lúc nào bạn cần ...


0

Câu trả lời cao nhất (Deepak Goel) không phù hợp với tôi. Bằng cách nào đó, thẻ không được thêm đúng cách.

Cuối cùng, tôi chỉ gửi ID của phân đoạn thông qua luồng (sử dụng ý định) và truy xuất nó trực tiếp từ trình quản lý phân đoạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.