Fragment.onAttachは、FragmentがActivityにアタッチされた時に呼ばれる。
アタッチって表現が難しい(紐付けられると言えばそう)のだが、ここに来ると、Activityを参照できるようになるらしい。
それはさておいて、Activityへのコールバックについて試してみる。
strings.xmlで、
Fragmentを2つ使うので、ButtonもTextViewもそれぞれに。
activity_main.xmlは、
FrameLayoutを中に。
fragment1_main.xmlは、
TextViewとButton。
fragment2_main.xmlも、
同じ。
CustomListener.javaを追加し、
package com.bgstation0.android.sample.fragment_; // カスタムリスナー public interface CustomListener { void onButtonClicked(); // ボタンが押された時. }
ボタンを押された時の独自コールバック。
Fragment1.javaで、
package com.bgstation0.android.sample.fragment_; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; // フラグメント1 public class Fragment1 extends Fragment { // メンバフィールド static final String TAG = "Fragment1"; // TAGを"Fragment1"で初期化. private CustomListener mCustomListener = null; // mCustomListenerをnullで初期化. // コンストラクタ public Fragment1(){ } // ファクトリメソッド public static Fragment1 newInstance(){ // Fragment1オブジェクトの生成. Fragment1 fragment1 = new Fragment1(); // fragment1を生成. return fragment1; // fragment1を返す. } // カスタムリスナーのセット. public void setCustomListener(CustomListener listener){ // リスナーのセット. mCustomListener = listener; // mCustomListenerにlistenerをセット. } // ビュー生成時 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // 既定の処理. super.onCreateView(inflater, container, savedInstanceState); // viewを返す. View view = inflater.inflate(R.layout.fragment1_main, null); // viewを作成. Button button = (Button)view.findViewById(R.id.fragment1_button); // buttonを取得. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // リスナーを実行. mCustomListener.onButtonClicked(); } }); return view; // viewを返す. } }
setCustomListenerで渡されたコールバックをセット。
Buttonが押されたら、実行。
Fragment2.javaも、
package com.bgstation0.android.sample.fragment_; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; // フラグメント1 public class Fragment2 extends Fragment { // メンバフィールド static final String TAG = "Fragment2"; // TAGを"Fragment2"で初期化. private CustomListener mCustomListener = null; // mCustomListenerをnullで初期化. // コンストラクタ public Fragment2(){ } // ファクトリメソッド public static Fragment2 newInstance(){ // Fragment2オブジェクトの生成. Fragment2 fragment2 = new Fragment2(); // fragment2を生成. return fragment2; // fragment2を返す. } // カスタムリスナーのセット. public void setCustomListener(CustomListener listener){ // リスナーのセット. mCustomListener = listener; // mCustomListenerにlistenerをセット. } // ビュー生成時 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // 既定の処理. super.onCreateView(inflater, container, savedInstanceState); // viewを返す. View view = inflater.inflate(R.layout.fragment2_main, null); // viewを作成. Button button = (Button)view.findViewById(R.id.fragment2_button); // buttonを取得. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // リスナーを実行. mCustomListener.onButtonClicked(); } }); return view; // viewを返す. } }
同じ。
MainActivity.javaは、
package com.bgstation0.android.sample.fragment_; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; // メインアクティビティ public class MainActivity extends Activity { // メンバフィールド static final String TAG = "MainActivity"; // TAGを"MainActivity"で初期化. Context mContext = null; // mContextをnullで初期化. // 生成時. @Override protected void onCreate(Bundle savedInstanceState) { // 既定の処理. super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; // mContextにthisをセット. if (savedInstanceState == null){ // Fragmentの追加. FragmentManager fragmentManager = getFragmentManager(); // fragmentManagerの取得. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // fragmentTransactionの開始. Fragment1 fragment1 = Fragment1.newInstance(); // fragment1を生成. fragment1.setCustomListener(new CustomListener(){ @Override public void onButtonClicked(){ Toast.makeText(mContext, TAG + " Callback", Toast.LENGTH_LONG).show(); // Toast表示. } }); fragmentTransaction.replace(R.id.framelayout1, fragment1); // fragment1に置換. fragmentTransaction.commit(); // 確定. } } }
fragment1.setCustomListenerの引数で、CustomListenerを定義してる。
Buttonが押されたらToast表示。
このFragmentを置換。
起動時。
Button押すと、
Toast表示。
回転して、Buttonを押すと、
おや?
落ちる。
回転するとコールバックのセットが無いから。
そこで、
package com.bgstation0.android.sample.fragment_; import android.app.Activity; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; // メインアクティビティ public class MainActivity extends Activity implements CustomListener{ // メンバフィールド static final String TAG = "MainActivity"; // TAGを"MainActivity"で初期化. Context mContext = null; // mContextをnullで初期化. // 生成時. @Override protected void onCreate(Bundle savedInstanceState) { // 既定の処理. super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; // mContextにthisをセット. if (savedInstanceState == null){ // Fragmentの追加. FragmentManager fragmentManager = getFragmentManager(); // fragmentManagerの取得. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); // fragmentTransactionの開始. Fragment1 fragment1 = Fragment1.newInstance(); // fragment1を生成. fragmentTransaction.replace(R.id.framelayout1, fragment1); // fragment1に置換. fragmentTransaction.commit(); // 確定. } } @Override public void onButtonClicked(){ Toast.makeText(mContext, TAG + " Callback", Toast.LENGTH_LONG).show(); // Toast表示. } }
MainActivity.javaで、CustomListenerのonButtonClickedを実装してしまう。
package com.bgstation0.android.sample.fragment_; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; // フラグメント1 public class Fragment1 extends Fragment { // メンバフィールド static final String TAG = "Fragment1"; // TAGを"Fragment1"で初期化. // コンストラクタ public Fragment1(){ } // ファクトリメソッド public static Fragment1 newInstance(){ // Fragment1オブジェクトの生成. Fragment1 fragment1 = new Fragment1(); // fragment1を生成. return fragment1; // fragment1を返す. } // ビュー生成時 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // 既定の処理. super.onCreateView(inflater, container, savedInstanceState); // viewを返す. View view = inflater.inflate(R.layout.fragment1_main, null); // viewを作成. Button button = (Button)view.findViewById(R.id.fragment1_button); // buttonを取得. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // リスナーを実行. ((MainActivity)getActivity()).onButtonClicked(); } }); return view; // viewを返す. } }
getActivityで取得したActivityをMainActivityにキャストして、onButtonClickedを呼べば、コールバック呼べてしまう。
setCustomListenerもいらないし。
package com.bgstation0.android.sample.fragment_; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; // フラグメント1 public class Fragment1 extends Fragment { // メンバフィールド static final String TAG = "Fragment1"; // TAGを"Fragment1"で初期化. private CustomListener mCustomListener = null; // mCustomListenerをnullで初期化. // コンストラクタ public Fragment1(){ } // ファクトリメソッド public static Fragment1 newInstance(){ // Fragment1オブジェクトの生成. Fragment1 fragment1 = new Fragment1(); // fragment1を生成. return fragment1; // fragment1を返す. } // アタッチ時 @Override public void onAttach(Activity activity){ // 既定の処理. super.onAttach(activity); mCustomListener = (CustomListener)activity; // activityをmCustomListenerに渡す. } // ビュー生成時 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // 既定の処理. super.onCreateView(inflater, container, savedInstanceState); // viewを返す. View view = inflater.inflate(R.layout.fragment1_main, null); // viewを作成. Button button = (Button)view.findViewById(R.id.fragment1_button); // buttonを取得. button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub // リスナーを実行. mCustomListener.onButtonClicked(); } }); return view; // viewを返す. } }
onArrachでActivityが渡されるので、それをmCustomListenerに保持しておいてもいい。
ここにonAttachの使いどころがある。
回転前もToastが出る。
回転後も落ちずにToast出る。
これで、コールバックはできたけど、最後にFragmentの中からActivityに飛んで、ActivityからFragmentの存在に関わる処理をしても、問題ないか試す。
CustomListener.javaで、
intの引数noをもらう。
Fragment1.javaで、
mCustomListener.onButtonClickedで1を渡す。
Fragment2.javaでは、
2を渡す。
MainActivity.javaでは、
1の時は2に置換、2の時は1を置換。
Buttonを押したら、別の片方に切り替わるということ。
Button1を押すと、
Fragment2に切り替わる。
横にしてButton2を押すと、
Fragment1に戻る。
このような切り替えができるので、ActivityからFragmentの存在に関わる処理が出来る。
Sample/android/Fragment/onAttach/src/Fragment at master · bg1bgst333/Sample · GitHub