いくつかのフラグメントを処理するアクティビティがあります。すべてのフラグメントには、いくつかのビューがあります(EditText, ListView, Map
など)。
その時点で表示されているフラグメントのインスタンスを保存するにはどうすればよいですか?アクティビティがonPause() --> onResume()
のときに動作する必要があります。また、別のフラグメント(バックスタックからポップ)から戻るときに機能する必要があります。
メイン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();
}}
次に、フラグメントの1つのコードを示します。
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();
});
}}
私は多くの情報を検索しましたが、明確なものはありません。誰かが明確な解決策と例を教えてもらえますか?
フラグメントがバックスタックに移動されても、破壊されません。すべてのインスタンス変数がそこに残ります。これがデータを保存する場所です。 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();
}
}
}
}
Androidフラグメントには、いくつかの利点と欠点があります。フラグメントの最も不利な点は、フラグメントを使用するときにフラグメントを作成することです。使用すると、フラグメントのonCreateView
が毎回呼び出されます。フラグメント内のコンポーネントの状態を保持する場合は、フラグメントの状態を保存する必要があり、次に示すようにその状態をロードする必要があります。これにより、フラグメントビューが少し遅くなり、奇妙になります。
私は解決策を見つけ、この解決策を使用しました。「すべてが素晴らしい。すべての人が試すことができます」。
初めてonCreateView
を実行するときは、グローバル変数としてビューを作成します。このフラグメントを2回目に呼び出すと、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);
}
これを試して :
@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();
}
これが役立つことを願っています。
また、これをmenifestファイルのアクティビティタグに書き込むことができます:
Android:configChanges="orientation|screenSize"
幸運を !!!
フラグメントの状態を保存するには、onSaveInstanceState()
を実装する必要があります:「アクティビティのように、アクティビティのプロセスが強制終了され、フラグメントの状態を復元する必要がある場合、Bundleを使用してフラグメントの状態を保持できますアクティビティの再作成時に、フラグメントのonSaveInstanceState()
コールバック中に状態を保存し、onCreate()
、onCreateView()
、またはonActivityCreated()
のいずれかで復元できます。 、アクティビティドキュメントをご覧ください。」
http://developer.Android.com/guide/components/fragments.html#Lifecycle
ここで述べたように: 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);
}
}
FragmentManagerから現在のフラグメントを取得できます。そして、フラグメントマネージャにそれらのどれもない場合は、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()
メソッドを無視し、アプリケーションがバックグラウンドになり、アプリケーションを強制終了して、必要なすべてのデータを保存するために必要なメモリを割り当てます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");
}
}
この質問がまだあなたを悩ませているのかどうかは、数ヶ月前からわかりません。しかし、私はこれに対処した方法を共有したいと思います。ソースコードは次のとおりです。
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は子にすでに親の物があるので、中間の親ビューとして別の親を使用することにしました。それが動作する方法です。
お役に立てば幸いです。