回転した時に、ActivityやFragmentの状態を保持する方法はいろいろある。
strings.xmlで、
Fragment1の中にTextViewとButton。
fragment1_main.xmlは、
このようにTextViewとButton。
activity_main.xmlは、
FrameLayoutだけ。
Fragment1.javaは、
package com.bgstation0.android.sample.fragment_; import android.app.Fragment; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; //フラグメント1 public class Fragment1 extends Fragment implements OnClickListener{ // メンバフィールド static final String TAG = "Fragment1"; // TAGを"Fragment1"で初期化. public int mNumber = 0; // mNumberを0で初期化. // コンストラクタ public Fragment1(){ } // フラグメント生成時 @Override public void onCreate(Bundle savedInstanceState){ // 既定の処理. super.onCreate(savedInstanceState); // 親クラスのonCreateを呼ぶ. // ログを残す. Log.d(TAG, "Fragment1.onCreate"); // "Fragment1.onCreate"とログに残す. } // フラグメント破棄時 @Override public void onDestroy(){ // ログを残す. Log.d(TAG, "Fragment1.onDestroy"); // "Fragment1.onDestroy"とログに残す. // 既定の処理. super.onDestroy(); // 親クラスのonDestroyを呼ぶ. } // ビュー生成時 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // ログを残す. Log.d(TAG, "Fragment1.onCreateView"); // "Fragment1.onCreateView"とログに残す. // 既定の処理. View view = inflater.inflate(R.layout.fragment1_main, null); // inflater.inflateでR.layout.fragment1_mainからビューを作成. Button button1 = (Button)view.findViewById(R.id.fragment1_button1); // Fragment1のbutton1を取得. button1.setOnClickListener(this); // リスナーとしてthisをセット. TextView tv = (TextView)view.findViewById(R.id.fragment1_textview); tv.setText(Integer.toString(mNumber)); return view; } @Override public void onClick(View v) { // TODO Auto-generated method stub mNumber++; // mNumberを増やす. View view = getView(); TextView tv = (TextView)view.findViewById(R.id.fragment1_textview); tv.setText(Integer.toString(mNumber)); } }
Buttonを押したら、mNumberを増やして、TextViewに表示。
MainActivity.javaは、
生成時、Fragment1を追加。
funcというログ出力だけのメソッドを用意。
ここまでやって最初は、
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bgstation0.android.sample.fragment_" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
普通のAndroidManifest.xmlにしている。
起動時。
Buttonを押すと、
TextViewの数値が増える。
横にすると、
数値は0に戻る。
数値を維持したい場合、
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.bgstation0.android.sample.fragment_" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden|screenSize" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
android:configChangesのorientationで、回転時のActivity/Fragment再生成を阻止できる。
起動時。
Buttonで増える。
確かに維持はできてる。
Activityは再生成されない。
Fragmentも回転による再生成では呼ばれていない。これは起動時の生成。
ところでアクションバーのドロイド君アイコンが小さくなっていることに気付いただろうか。
android:configChangesのorientationだと、Activity/Fragmentが再生成されないので、向きによってデザインを変えたり、UIを意図的に更新したり、見た目上のアイコンの大きさを変えないとか、再生成されないと困る場合が少しある。
Activityは再生成させ、Fragmentは再生成させない方法が、Fragment.setRetainInstanceをtrueにすること。
AndroidManifest.xmlを、
元に戻して、Fragment1.javaを、
onCreateでsetRetainInstanceをtrueに。
onAttachで引数のactivityをMainActivityのmContextにキャストしてfuncを呼んでいるが、これ自体はどうでもいいのだが、onDetachでmContextをnullにしているのが重要。参照したままだとメモリリークするらしい。
起動時。
Buttonで増やして、
回転で維持。アイコンも見た目上の大きさは変わらない。
Fragment1がonDetachされているのにonDestroyされていないのが破棄されていない証拠。
mCurrentFragmentでインスタンスがまったく同じなのもわかる。
(あくまでFragmentインスタンスが維持されるかどうかの話がメインで、アクションバーのアイコンやテキストの大きさについてはいずれ別途扱った方がいいかも。混乱誤解を生みやすいし僕も理解できてない。)
Sample/android/Fragment/setRetainInstance/src/Fragment at master · bg1bgst333/Sample · GitHub