刷新 SwipeRefreshLayout 时,不会立即提交(不会发生)显示和隐藏片段
Showing and hiding fragments are not committed (don't occur) immediately when SwipeRefreshLayout is refreshing
所以基本上我正在做的工作与 Instagram 应用程序非常相似,其中有许多选项卡,用户可以毫不延迟地切换到任何选项卡,无论发生什么事情,例如刷新,重新加载等。它还使用后退按钮返回到上一个保留的选项卡。
为了实现这一点,我使用 FragmentManager
和 FragmentTransaction
来显示和隐藏代表每个选项卡的每个片段。我没有使用 replace
或 attach
/ detach
因为它们会破坏上一个选项卡的视图层次结构。
我的实现工作得很好,除了显示和隐藏片段没有提交(我非常怀疑这是一个正确的词,但到目前为止我是这样理解流程的。),或者不立即发生 当 SwipeRefreshLayout
刷新添加到 FragmentManager
的片段(要隐藏)时,该片段晚于要显示的片段 。
我的实现遵循这些规则。假设我们有 4 个选项卡,我的 MainActivity 显示第一个选项卡,比如 FirstFragment,用户选择第二个选项卡,第二个片段。因为以前从未添加过 SecondFragment,所以我使用 FragmentTransaction.add
将其添加到 FragmentManager
并使用 [=隐藏 FirstFragment FragmentTransaction.hide
。如果用户再次选择第一个选项卡,因为 FirstFragment 之前已添加到 FragmentManager
,它不会添加,只会显示 FirstFragment并隐藏 SecondFragment。在这两个选项卡之间进行选择可以顺利进行。
但是当用户 "refreshes" SecondFragment 的 SwipeRefreshLayout
并选择第一个选项卡时,FragmentTransaction
等待 SecondFragment 的刷新将完成并提交(?)实际事务。奇怪的是,从FirstFragment的刷新到SecondFragment.
,事务是立即提交的
因为这是按添加到 FragmentManager
的顺序发生的,我怀疑添加顺序会以某种方式影响片段的回栈,并且可能存在类似 UI 线程优先级的东西,因此它强制片段事务将在稍后添加的片段的 UI 转换完成后发生。但我只是没有足够的线索来解决这个问题。我已经尝试在 FragmentTransaction
上附加/分离和回退,但无法解决问题。 FragmentTransaction.commit
和 FragmentTransaction.commitAllowingStateLoss
我都试过了,但都没有解决问题。
这些是我的 MainActivity 的示例代码。
private ArrayList<Integer> mFragmentsStack; // This is simple psuedo-stack which only stores
// the order of fragments stack to collaborate
// when back button is pressed.
private ArrayList<Fragment> mFragmentsList;
@Override
protected void onCreate() {
mFragmentsStack = new ArrayList<>();
mFragmentsList = new ArrayList<>();
mFragmentsList.add(FirstFragment.newInstance());
mFragmentsList.add(SecondFragment.newInstance());
mFragmentsList.add(ThirdFragment.newInstance());
mFragmentsList.add(FourthFragment.newInstance());
mMainTab = (MainTab) findViewById(R.id.main_tab);
mMainTab.setOnMainTabClickListener(this);
int currentTab = DEFAULT_TAB;
mFragmentsStack.add(currentTab);
getSupportFragmentManager().beginTransaction().add(R.id.main_frame_layout,
mFragmentsList.get(currentTab), String.valueOf(currentTab)).commit();
mMainTab.setCurrentTab(currentTab);
}
// This is custom interface.
@Override
public void onTabClick(int oldPosition, int newPosition) {
if (oldPosition != newPosition) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
// First hide the old tab.
fragmentTransaction.hide(mFragmentsList.get(oldPosition));
// Recalculate the fragment stack.
if (mFragmentsStack.contains(newPosition)) {
mFragmentsStack.remove((Integer) newPosition);
}
mFragmentsStack.add(newPosition);
// Add new fragment if it's not added before, or show new fragment which was already hidden.
Fragment fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(newPosition));
if (fragment != null) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.add(R.id.main_frame_layout, mFragmentsList.get(newPosition),
String.valueOf(newPosition));
}
// Commit the transaction.
fragmentTransaction.commitAllowingStateLoss();
}
}
// It mimics the tab behavior of Instagram Android application.
@Override
public void onBackPressed() {
// If there's only one fragment on stack, super.onBackPressed.
// If it's not, then hide the current fragment and show the previous fragment.
int lastIndexOfFragmentsStack = mFragmentsStack.size() - 1;
if (lastIndexOfFragmentsStack - 1 >= 0) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack)));
fragmentTransaction.show(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack - 1)));
fragmentTransaction.commitAllowingStateLoss();
mMainTab.setCurrentTab(mFragmentsStack.get(lastIndexOfFragmentsStack - 1));
mFragmentsStack.remove(lastIndexOfFragmentsStack);
} else {
super.onBackPressed();
}
}
刚遇到同样的问题,唯一不同的是 - 我在点击工具栏按钮时切换片段。
我设法摆脱了覆盖 onHiddenChanged 的重叠片段:
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
yourSwipeRefreshLayout.setRefreshing(false);
}
}
所以基本上我正在做的工作与 Instagram 应用程序非常相似,其中有许多选项卡,用户可以毫不延迟地切换到任何选项卡,无论发生什么事情,例如刷新,重新加载等。它还使用后退按钮返回到上一个保留的选项卡。
为了实现这一点,我使用 FragmentManager
和 FragmentTransaction
来显示和隐藏代表每个选项卡的每个片段。我没有使用 replace
或 attach
/ detach
因为它们会破坏上一个选项卡的视图层次结构。
我的实现工作得很好,除了显示和隐藏片段没有提交(我非常怀疑这是一个正确的词,但到目前为止我是这样理解流程的。),或者不立即发生 当 SwipeRefreshLayout
刷新添加到 FragmentManager
的片段(要隐藏)时,该片段晚于要显示的片段 。
我的实现遵循这些规则。假设我们有 4 个选项卡,我的 MainActivity 显示第一个选项卡,比如 FirstFragment,用户选择第二个选项卡,第二个片段。因为以前从未添加过 SecondFragment,所以我使用 FragmentTransaction.add
将其添加到 FragmentManager
并使用 [=隐藏 FirstFragment FragmentTransaction.hide
。如果用户再次选择第一个选项卡,因为 FirstFragment 之前已添加到 FragmentManager
,它不会添加,只会显示 FirstFragment并隐藏 SecondFragment。在这两个选项卡之间进行选择可以顺利进行。
但是当用户 "refreshes" SecondFragment 的 SwipeRefreshLayout
并选择第一个选项卡时,FragmentTransaction
等待 SecondFragment 的刷新将完成并提交(?)实际事务。奇怪的是,从FirstFragment的刷新到SecondFragment.
因为这是按添加到 FragmentManager
的顺序发生的,我怀疑添加顺序会以某种方式影响片段的回栈,并且可能存在类似 UI 线程优先级的东西,因此它强制片段事务将在稍后添加的片段的 UI 转换完成后发生。但我只是没有足够的线索来解决这个问题。我已经尝试在 FragmentTransaction
上附加/分离和回退,但无法解决问题。 FragmentTransaction.commit
和 FragmentTransaction.commitAllowingStateLoss
我都试过了,但都没有解决问题。
这些是我的 MainActivity 的示例代码。
private ArrayList<Integer> mFragmentsStack; // This is simple psuedo-stack which only stores
// the order of fragments stack to collaborate
// when back button is pressed.
private ArrayList<Fragment> mFragmentsList;
@Override
protected void onCreate() {
mFragmentsStack = new ArrayList<>();
mFragmentsList = new ArrayList<>();
mFragmentsList.add(FirstFragment.newInstance());
mFragmentsList.add(SecondFragment.newInstance());
mFragmentsList.add(ThirdFragment.newInstance());
mFragmentsList.add(FourthFragment.newInstance());
mMainTab = (MainTab) findViewById(R.id.main_tab);
mMainTab.setOnMainTabClickListener(this);
int currentTab = DEFAULT_TAB;
mFragmentsStack.add(currentTab);
getSupportFragmentManager().beginTransaction().add(R.id.main_frame_layout,
mFragmentsList.get(currentTab), String.valueOf(currentTab)).commit();
mMainTab.setCurrentTab(currentTab);
}
// This is custom interface.
@Override
public void onTabClick(int oldPosition, int newPosition) {
if (oldPosition != newPosition) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
// First hide the old tab.
fragmentTransaction.hide(mFragmentsList.get(oldPosition));
// Recalculate the fragment stack.
if (mFragmentsStack.contains(newPosition)) {
mFragmentsStack.remove((Integer) newPosition);
}
mFragmentsStack.add(newPosition);
// Add new fragment if it's not added before, or show new fragment which was already hidden.
Fragment fragment = getSupportFragmentManager().findFragmentByTag(String.valueOf(newPosition));
if (fragment != null) {
fragmentTransaction.show(fragment);
} else {
fragmentTransaction.add(R.id.main_frame_layout, mFragmentsList.get(newPosition),
String.valueOf(newPosition));
}
// Commit the transaction.
fragmentTransaction.commitAllowingStateLoss();
}
}
// It mimics the tab behavior of Instagram Android application.
@Override
public void onBackPressed() {
// If there's only one fragment on stack, super.onBackPressed.
// If it's not, then hide the current fragment and show the previous fragment.
int lastIndexOfFragmentsStack = mFragmentsStack.size() - 1;
if (lastIndexOfFragmentsStack - 1 >= 0) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.hide(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack)));
fragmentTransaction.show(mFragmentsList.get(mFragmentsStack.get(lastIndexOfFragmentsStack - 1)));
fragmentTransaction.commitAllowingStateLoss();
mMainTab.setCurrentTab(mFragmentsStack.get(lastIndexOfFragmentsStack - 1));
mFragmentsStack.remove(lastIndexOfFragmentsStack);
} else {
super.onBackPressed();
}
}
刚遇到同样的问题,唯一不同的是 - 我在点击工具栏按钮时切换片段。 我设法摆脱了覆盖 onHiddenChanged 的重叠片段:
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
yourSwipeRefreshLayout.setRefreshing(false);
}
}