我有一个活动,其中我经历了几个片段。在每个片段中,我都有几个视图(EditText, ListView, Map
等)。
如何保存当时显示的片段实例?当活动为onPause() --> onResume()
时,我需要它才能工作。当我从另一个片段(从backstack弹出)返回时,我需要它才能工作。
从主Activity
我调用第一个片段,然后从片段中调用下一个片段。
我的活动代码:
public class Activity_Main extends FragmentActivity{
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
fragment_1 = new Fragment_1();
fragment_2 = new Fragment_2();
fragment_3 = new Fragment_3();
fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction_1 = fragmentManager.beginTransaction();
transaction_1.replace(R.id.content_frame, fragment_1);
transaction_1.commit();
}}
然后这是我的一个片段的代码:
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public View onCreateView(final LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_1,
container, false);
title = (EditText) rootView.findViewById(R.id.title);
go_next = (Button) rootView.findViewById(R.id.go_next);
image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentTransaction transaction_2 = Activity_Main.fragmentManager
.beginTransaction();
transaction_2.replace(R.id.content_frame,
Activity_Main.fragment_2);
transaction_2.addToBackStack(null);
transaction_2.commit();
});
}}
我搜索了很多信息,但没有任何明确的信息。请问有人给出一个明确的解决方案和一个例子吗?
答案 0 :(得分:81)
当片段移动到后台堆栈时,它不会被销毁。所有实例变量都保留在那里。所以这是保存数据的地方。在onActivityCreated
中,您需要检查以下条件:
编辑:这是一个例子
public class ExampleFragment extends Fragment {
private List<String> myData;
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable("list", (Serializable) myData);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
//probably orientation change
myData = (List<String>) savedInstanceState.getSerializable("list");
} else {
if (myData != null) {
//returning from backstack, data is fine, do nothing
} else {
//newly created, compute data
myData = computeData();
}
}
}
}
答案 1 :(得分:15)
Android片段有一些优点和一些缺点。
片段的最大缺点是,当您想要使用片段时,您可以创建片段。
使用它时,每次都会调用片段的onCreateView
。如果要保留片段中组件的状态,则必须保存片段状态,并且必须在下一个显示中加载其状态。
这使片段视图有点慢和奇怪。
我找到了一个解决方案,并且我已经使用了这个解决方案:“一切都很棒。每个人都可以尝试”。
当第一次运行onCreateView
时,将视图创建为全局变量。当第二次调用此片段onCreateView
再次调用时,您可以返回此全局视图。将保留片段组件状态。
View view;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
setActionBar(null);
if (view != null) {
if ((ViewGroup)view.getParent() != null)
((ViewGroup)view.getParent()).removeView(view);
return view;
}
view = inflater.inflate(R.layout.mylayout, container, false);
}
答案 2 :(得分:7)
试试这个:
@Override
protected void onPause() {
super.onPause();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").setRetainInstance(true);
}
@Override
protected void onResume() {
super.onResume();
if (getSupportFragmentManager().findFragmentByTag("MyFragment") != null)
getSupportFragmentManager().findFragmentByTag("MyFragment").getRetainInstance();
}
希望这会有所帮助。
此外,您可以将此内容写入清单文件中的活动代码:
android:configChanges="orientation|screenSize"
祝你好运!!!
答案 3 :(得分:4)
为了保存Fragment状态,您需要实现onSaveInstanceState()
:
&#34;与活动类似,您可以使用Bundle保留片段的状态,以防活动的进程被终止,并且您需要在重新创建活动时恢复片段状态。您可以在片段onSaveInstanceState()
回调期间保存状态,并在onCreate()
,onCreateView()
或onActivityCreated()
期间恢复该状态。有关保存状态的更多信息,请参阅活动文档。&#34;
http://developer.android.com/guide/components/fragments.html#Lifecycle
答案 4 :(得分:3)
如上所述:Why use Fragment#setRetainInstance(boolean)?
你也可以像这样使用片段方法setRetainInstance(true)
:
public class MyFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// keep the fragment and all its data across screen rotation
setRetainInstance(true);
}
}
答案 5 :(得分:0)
您可以从fragmentManager获取当前的Fragment。如果片段管理器中没有它们,您可以创建Fragment_1
public class MainActivity extends FragmentActivity {
public static Fragment_1 fragment_1;
public static Fragment_2 fragment_2;
public static Fragment_3 fragment_3;
public static FragmentManager fragmentManager;
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.main);
fragment_1 = (Fragment_1) fragmentManager.findFragmentByTag("fragment1");
fragment_2 =(Fragment_2) fragmentManager.findFragmentByTag("fragment2");
fragment_3 = (Fragment_3) fragmentManager.findFragmentByTag("fragment3");
if(fragment_1==null && fragment_2==null && fragment_3==null){
fragment_1 = new Fragment_1();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment_1, "fragment1").commit();
}
}
}
你也可以使用setRetainInstance
来实现它会做什么忽略片段中的onDestroy()
方法并且你的应用程序会回到地面并且os会杀死你的应用程序以分配更多你需要保存所有内存的内存onSaveInstanceState
捆绑包
public class Fragment_1 extends Fragment {
private EditText title;
private Button go_next;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true); //Will ignore onDestroy Method (Nested Fragments no need this if parent have it)
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
onRestoreInstanceStae(savedInstanceState);
return super.onCreateView(inflater, container, savedInstanceState);
}
//Here you can restore saved data in onSaveInstanceState Bundle
private void onRestoreInstanceState(Bundle savedInstanceState){
if(savedInstanceState!=null){
String SomeText = savedInstanceState.getString("title");
}
}
//Here you Save your data
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("title", "Some Text");
}
}
答案 6 :(得分:0)
我不太确定这个问题是否仍然困扰着你,因为已经有好几个月了。但我想分享一下我是如何处理这个问题的。 这是源代码:
int FLAG = 0;
private View rootView;
private LinearLayout parentView;
/**
* The fragment argument representing the section number for this fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section number.
*/
public static Fragment2 newInstance(Bundle bundle) {
Fragment2 fragment = new Fragment2();
Bundle args = bundle;
fragment.setArguments(args);
return fragment;
}
public Fragment2() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.e("onCreateView","onCreateView");
if(FLAG!=12321){
rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false);
changeFLAG(12321);
}
parentView=new LinearLayout(getActivity());
parentView.addView(rootView);
return parentView;
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onDestroy()
*/
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e("onDestroy","onDestroy");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStart()
*/
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e("onstart","onstart");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStop()
*/
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(false){
Bundle savedInstance=getArguments();
LinearLayout viewParent;
viewParent= (LinearLayout) rootView.getParent();
viewParent.removeView(rootView);
}
parentView.removeView(rootView);
Log.e("onStop","onstop");
}
@Override
public void onPause() {
super.onPause();
Log.e("onpause","onpause");
}
@Override
public void onResume() {
super.onResume();
Log.e("onResume","onResume");
}
这是MainActivity:
/**
* Fragment managing the behaviors, interactions and presentation of the
* navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in
* {@link #restoreActionBar()}.
*/
public static boolean fragment2InstanceExists=false;
public static Fragment2 fragment2=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
switch(position){
case 0:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit();
break;
case 1:
Bundle bundle=new Bundle();
bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY);
if(!fragment2InstanceExists){
fragment2=Fragment2.newInstance(bundle);
fragment2InstanceExists=true;
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, fragment2).commit();
break;
case 2:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit();
break;
default:
break;
}
}
parentView
是关键点。
通常,在onCreateView
时,我们只使用return rootView
。但现在,我将rootView添加到parentView
,然后返回parentView
。要防止“指定的孩子已经有父母。你必须在...上调用removeView()
”错误,我们需要调用parentView.removeView(rootView)
,否则我提供的方法就没用了。
我也想分享我是如何找到它的。首先,我设置一个布尔值来指示实例是否存在。当实例存在时,rootView
将不会再次膨胀。但是后来,logcat给孩子已经有了父东西,所以我决定用另一个父亲作为中间父视图。这就是它的工作原理。
希望它对你有所帮助。
答案 7 :(得分:0)
如果您使用底部工具栏并插入viewpager,则要设置自定义片段替换逻辑,以获取先前的保存状态,则可以使用以下代码进行操作
String current_frag_tag = null;
String prev_frag_tag = null;
@Override
public void onTabSelected(TabLayout.Tab tab) {
switch (tab.getPosition()) {
case 0:
replaceFragment(new Fragment1(), "Fragment1");
break;
case 1:
replaceFragment(new Fragment2(), "Fragment2");
break;
case 2:
replaceFragment(new Fragment3(), "Fragment3");
break;
case 3:
replaceFragment(new Fragment4(), "Fragment4");
break;
default:
replaceFragment(new Fragment1(), "Fragment1");
break;
}
public void replaceFragment(Fragment fragment, String tag) {
if (current_frag_tag != null) {
prev_frag_tag = current_frag_tag;
}
current_frag_tag = tag;
FragmentManager manager = null;
try {
manager = requireActivity().getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
if (manager.findFragmentByTag(current_frag_tag) == null) { // No fragment in backStack with same tag..
ft.add(R.id.viewpagerLayout, fragment, current_frag_tag);
if (prev_frag_tag != null) {
try {
ft.hide(Objects.requireNonNull(manager.findFragmentByTag(prev_frag_tag)));
} catch (NullPointerException e) {
e.printStackTrace();
}
}
// ft.show(manager.findFragmentByTag(current_frag_tag));
ft.addToBackStack(current_frag_tag);
ft.commit();
} else {
try {
ft.hide(Objects.requireNonNull(manager.findFragmentByTag(prev_frag_tag)))
.show(Objects.requireNonNull(manager.findFragmentByTag(current_frag_tag))).commit();
} catch (NullPointerException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
您可以使用以下方法访问内部片段的碎片可见或不可见 注意:您必须在子片段中实现以下方法
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
try {
if(hidden){
adapter.getFragment(mainVideoBinding.viewPagerVideoMain.getCurrentItem()).onPause();
}else{
adapter.getFragment(mainVideoBinding.viewPagerVideoMain.getCurrentItem()).onResume();
}
}catch (Exception e){
}
}