Я не нашел простого способа получить все активные в данный момент (видимые, находящиеся в состоянии возобновления) фрагменты в действии. Возможно ли без пользовательской бухгалтерии в моей деятельности? Похоже, что FragmentManager не поддерживает эту функцию.
Есть ли способ получить ссылки на все активные в данный момент фрагменты в Activity?
Ответы (7)
Похоже, в настоящее время в API отсутствует такой метод, как "getFragments".
Однако с помощью события "onAttachFragment" класса Activity сделать то, что вы хотите, довольно просто. Я бы сделал что-то вроде:
List<WeakReference<Fragment>> fragList = new ArrayList<WeakReference<Fragment>>();
@Override
public void onAttachFragment (Fragment fragment) {
fragList.add(new WeakReference(fragment));
}
public List<Fragment> getActiveFragments() {
ArrayList<Fragment> ret = new ArrayList<Fragment>();
for(WeakReference<Fragment> ref : fragList) {
Fragment f = ref.get();
if(f != null) {
if(f.isVisible()) {
ret.add(f);
}
}
}
return ret;
}
В случае, если нет готового метода для чтения состояния объекта (isActive() в примере), я бы переопределил onResume и onPause, чтобы установить флаг (может быть просто логическое поле).
Это уже какая-то собственная бухгалтерия, но все же очень ограниченный, на мой взгляд, учитывая довольно конкретную цель, которую вы хотите достичь (список, зависящий от статуса).
onAttach
и onDetach
Fragment
в FragmentActivity
через расширенный интерфейс обратного вызова (обычно используемый для отправки уведомлений о выборе элемента во фрагменте). Методы добавляют фрагменты во внутренний список, а затем удаляют их из него. Кажется, работает без необходимости использовать WeakReference
s.
- person Stan; 31.10.2013
getFragments()
, но его не следует использовать. Он помечен @hide
и не должен был быть включен в jar библиотеки поддержки. Его не следует рассматривать как часть экспортируемого API.
- person James Wald; 25.03.2014
Если вы используете библиотеку поддержки Android, вы можете вызвать скрытый метод FragmentManager.getFragments()
:
public List<Fragment> getVisibleFragments() {
List<Fragment> allFragments = getSupportFragmentManager().getFragments();
if (allFragments == null || allFragments.isEmpty()) {
return Collections.emptyList();
}
List<Fragment> visibleFragments = new ArrayList<Fragment>();
for (Fragment fragment : allFragments) {
if (fragment.isVisible()) {
visibleFragments.add(fragment);
}
}
return visibleFragments;
}
@hide
и не должен был быть включен в jar библиотеки поддержки. Его не следует рассматривать как часть экспортируемого API.
- person James Wald; 25.03.2014
getFragments
ограничен библиотеками из одного и того же groupId, и Android Lint выдаст ошибку Lint, если вы его используете.
- person Nahuel Barrios; 10.03.2017
Другой способ сделать это — пометить фрагменты тегами, когда вы добавляете их в действие.
Например, если вы динамически добавляете 4 фрагмента, вы можете добавить их так:
for (int i = 0; i < NUM_FRAGMENTS; i++){
MyFragment fragment = new Fragment(i);
fragmentTransaction.add(R.id.containerId, fragment, SOME_CUSTOM_PREFIX + i).commit()
}
Затем, если вам нужно вернуть все фрагменты позже, вы можете сделать:
for (int i = 0; i < NUM_FRAGMENTS; i++) {
String tag = SOME_CUSTOM_PREFIX + i;
fragmentList.add((MyFragment) fragmentManager.findFragmentByTag(tag));
}
Я решил с этим:
public ArrayList<Fragment> getAllFragments() {
ArrayList<Fragment> lista = new ArrayList<Fragment>();
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
try {
fragment.getTag();
lista.add(fragment);
} catch (NullPointerException e) {
}
}
return lista;
}
android.support.v4.app.FragmentManager
есть метод getFragments()
, который делает именно то, что вам нужно, но он никогда не был доступен. Внезапно, однако, это так, но я не уверен, предназначено ли это, потому что он все еще помечен как скрытый.
/**
* Get a list of all fragments that have been added to the fragment manager.
*
* @return The list of all fragments or null if none.
* @hide
*/
public abstract List<Fragment> getFragments();
Обычный android.app.FragmentManager
вообще не имеет этого метода, но если действительно нужно, вы можете получить доступ к тому же объекту, получив поле mActive
через отражение (будьте осторожны: начиная с API 26, его тип — SparseArray
вместо List
). Используйте на свой страх и риск :)
Вот рекурсивное решение в Котлине. Учитывая самые верхние фрагменты действия, возвращает все дочерние фрагменты.
fun recursiveGetFragments(parents: List<Fragment>): List<Fragment> {
val result = parents.toMutableList()
for(root in parents) {
if (root.isVisible) {
result.addAll(recursiveGetFragments(root.childFragmentManager.fragments))
}
}
return result
}
Он используется как:
val fragmentList = recursiveGetFragments(supportFragmentManager.fragments)
мы можем использовать какой-то неправильный, но законный метод
ArrayList<Fragment> getActiveFragments() {
Fragment f;
final ArrayList<Fragment> fragments = new ArrayList<>();
int i = 0;
try {
while ((f = getFragmentManager().getFragment(new Intent().putExtra("anyvalue", i++).getExtras(), "anyvalue")) != null) {
fragments.add(f);
}
} catch (IllegalStateException ex) {
}
return fragments;
}