我正在使用兼容包将Fragments与Android 2.2一起使用。 当使用片段,并在它们之间添加转换到backstack时,我想实现活动的onResume的相同行为,即,在弹出一个片段到达“前景”(用户可见)之后backstack,我想在片段中激活某种回调(例如,在共享UI资源上执行某些更改)。
我看到片段框架中没有内置回调。为了达到这个目的,有一个很好的做法吗?
答案 0 :(得分:110)
由于缺乏更好的解决方案,我认为这对我有用: 假设我有1个活动(MyActivity)和几个相互替换的片段(一次只能看到一个)。
在MyActivity中,添加此侦听器:
getSupportFragmentManager().addOnBackStackChangedListener(getListener());
(如您所见,我正在使用兼容包)。
getListener实施:
private OnBackStackChangedListener getListener()
{
OnBackStackChangedListener result = new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
FragmentManager manager = getSupportFragmentManager();
if (manager != null)
{
MyFragment currFrag = (MyFragment) manager.findFragmentById(R.id.fragmentItem);
currFrag.onFragmentResume();
}
}
};
return result;
}
按下“后退”后将调用 MyFragment.onFragmentResume()
。但有几点需要注意:
FragmentTransaction.addToBackStack()
)答案 1 :(得分:32)
我已经改变了建议的解决方案。对我来说效果更好:
private OnBackStackChangedListener getListener() {
OnBackStackChangedListener result = new OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager manager = getSupportFragmentManager();
if (manager != null) {
int backStackEntryCount = manager.getBackStackEntryCount();
if (backStackEntryCount == 0) {
finish();
}
Fragment fragment = manager.getFragments()
.get(backStackEntryCount - 1);
fragment.onResume();
}
}
};
return result;
}
答案 2 :(得分:5)
在popStackBack()
之后,您可以在片段中使用以下回调:onHiddenChanged(boolean hidden)
答案 3 :(得分:3)
Android开发者的以下部分介绍了一种通信机制Creating event callbacks to the activity。引用它的一行:
这样做的一个好方法是在片段内定义一个回调接口,并要求主机活动实现它。当活动通过接口收到回调时,它可以根据需要与布局中的其他片段共享信息。
修改强>
片段具有onStart(...)
,当片段对用户可见时调用该片段。类似地,onResume(...)
在可见并且正在运行时。这些与他们的活动对应物有关。
简而言之:使用onResume()
答案 4 :(得分:2)
略微改进并包含在经理解决方案中。
要记住的事情。 FragmentManager不是单例,它只管理Activity中的Fragments,因此在每个活动中它都是新的。此外,到目前为止,这个解决方案并不考虑ViewPager,它调用setUserVisibleHint()方法来帮助控制碎片的可见性。
在处理此问题时,请随意使用以下类(使用Dagger2注入)。呼叫活动:
//inject FragmentBackstackStateManager instance to myFragmentBackstackStateManager
FragmentManager fragmentManager = getSupportFragmentManager();
myFragmentBackstackStateManager.apply(fragmentManager);
FragmentBackstackStateManager.java:
@Singleton
public class FragmentBackstackStateManager {
private FragmentManager fragmentManager;
@Inject
public FragmentBackstackStateManager() {
}
private BackstackCallback backstackCallbackImpl = new BackstackCallback() {
@Override
public void onFragmentPushed(Fragment parentFragment) {
parentFragment.onPause();
}
@Override
public void onFragmentPopped(Fragment parentFragment) {
parentFragment.onResume();
}
};
public FragmentBackstackChangeListenerImpl getListener() {
return new FragmentBackstackChangeListenerImpl(fragmentManager, backstackCallbackImpl);
}
public void apply(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
fragmentManager.addOnBackStackChangedListener(getListener());
}
}
FragmentBackstackChangeListenerImpl.java:
public class FragmentBackstackChangeListenerImpl implements FragmentManager.OnBackStackChangedListener {
private int lastBackStackEntryCount = 0;
private final FragmentManager fragmentManager;
private final BackstackCallback backstackChangeListener;
public FragmentBackstackChangeListenerImpl(FragmentManager fragmentManager, BackstackCallback backstackChangeListener) {
this.fragmentManager = fragmentManager;
this.backstackChangeListener = backstackChangeListener;
lastBackStackEntryCount = fragmentManager.getBackStackEntryCount();
}
private boolean wasPushed(int backStackEntryCount) {
return lastBackStackEntryCount < backStackEntryCount;
}
private boolean wasPopped(int backStackEntryCount) {
return lastBackStackEntryCount > backStackEntryCount;
}
private boolean haveFragments() {
List<Fragment> fragmentList = fragmentManager.getFragments();
return fragmentList != null && !fragmentList.isEmpty();
}
/**
* If we push a fragment to backstack then parent would be the one before => size - 2
* If we pop a fragment from backstack logically it should be the last fragment in the list, but in Android popping a fragment just makes list entry null keeping list size intact, thus it's also size - 2
*
* @return fragment that is parent to the one that is pushed to or popped from back stack
*/
private Fragment getParentFragment() {
List<Fragment> fragmentList = fragmentManager.getFragments();
return fragmentList.get(Math.max(0, fragmentList.size() - 2));
}
@Override
public void onBackStackChanged() {
int currentBackStackEntryCount = fragmentManager.getBackStackEntryCount();
if (haveFragments()) {
Fragment parentFragment = getParentFragment();
//will be null if was just popped and was last in the stack
if (parentFragment != null) {
if (wasPushed(currentBackStackEntryCount)) {
backstackChangeListener.onFragmentPushed(parentFragment);
} else if (wasPopped(currentBackStackEntryCount)) {
backstackChangeListener.onFragmentPopped(parentFragment);
}
}
}
lastBackStackEntryCount = currentBackStackEntryCount;
}
}
BackstackCallback.java:
public interface BackstackCallback {
void onFragmentPushed(Fragment parentFragment);
void onFragmentPopped(Fragment parentFragment);
}
答案 5 :(得分:2)
在我的活动onCreate()
中getSupportFragmentManager().addOnBackStackChangedListener(getListener());
使用此方法捕获特定的Fragment并调用onResume()
private FragmentManager.OnBackStackChangedListener getListener()
{
FragmentManager.OnBackStackChangedListener result = new FragmentManager.OnBackStackChangedListener()
{
public void onBackStackChanged()
{
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if (currentFragment instanceof YOURFRAGMENT) {
currentFragment.onResume();
}
}
};
return result;
}
答案 6 :(得分:1)
如果片段放在backstack上,Android只会破坏其视图。片段实例本身未被杀死。一个简单的启动方法应该是监听onViewCreated事件,并在那里设置“onResume()”逻辑。
boolean fragmentAlreadyLoaded = false;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null && !fragmentAlreadyLoaded) {
fragmentAlreadyLoaded = true;
// Code placed here will be executed once
}
//Code placed here will be executed even when the fragment comes from backstack
}
答案 7 :(得分:0)
这是您可以调用onResume()的正确答案,前提是片段已附加到活动中。或者,您可以使用onAttach和onDetach
答案 8 :(得分:0)
onResume()工作得很好......
public class listBook extends Fragment {
private String listbook_last_subtitle;
...
@Override
public void onCreate(Bundle savedInstanceState) {
String thisFragSubtitle = (String) getActivity().getActionBar().getSubtitle();
listbook_last_subtitle = thisFragSubtitle;
}
...
@Override
public void onResume(){
super.onResume();
getActivity().getActionBar().setSubtitle(listbook_last_subtitle);
}
...
答案 9 :(得分:0)
public abstract class RootFragment extends Fragment implements OnBackPressListener {
@Override
public boolean onBackPressed() {
return new BackPressImpl(this).onBackPressed();
}
public abstract void OnRefreshUI();
}
public class BackPressImpl implements OnBackPressListener {
private Fragment parentFragment;
public BackPressImpl(Fragment parentFragment) {
this.parentFragment = parentFragment;
}
@Override
public boolean onBackPressed() {
((RootFragment) parentFragment).OnRefreshUI();
}
}
并最终将你的Frament从RootFragment扩展到效果
答案 10 :(得分:0)
我的解决方法是在将片段设置为新标题之前获取片段中操作栏的当前标题。这样,一旦弹出片段,我就可以改回那个标题。
@Override
public void onResume() {
super.onResume();
// Get/Backup current title
mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
.getTitle();
// Set new title
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(R.string.this_fragment_title);
}
@Override
public void onDestroy() {
// Set title back
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(mTitle);
super.onDestroy();
}
答案 11 :(得分:0)
我使用enum FragmentTags
来定义我的所有片段类。
TAG_FOR_FRAGMENT_A(A.class),
TAG_FOR_FRAGMENT_B(B.class),
TAG_FOR_FRAGMENT_C(C.class)
将FragmentTags.TAG_FOR_FRAGMENT_A.name()
作为片段标记传递。
现在
@Override
public void onBackPressed(){
FragmentManager fragmentManager = getFragmentManager();
Fragment current
= fragmentManager.findFragmentById(R.id.fragment_container);
FragmentTags fragmentTag = FragmentTags.valueOf(current.getTag());
switch(fragmentTag){
case TAG_FOR_FRAGMENT_A:
finish();
break;
case TAG_FOR_FRAGMENT_B:
fragmentManager.popBackStack();
break;
case default:
break;
}