《Android》『Interface』- 利用 Interface 於 MainActivity 中控管 Fragment 與 onBackPressed
《Android Developers 參考文獻》
《簡單介紹》
在使用 Fragment 的過程中,我們為了管理方便,通常會將所有控制頁面切換的機制寫在 MainActivity 中,盡量避免直接在一個 Fragment 中跳轉至另一個 Fragment,這樣做的目的是,當 Fragment 變得越來越多時,才不會變得難以控管與維護,利用 implements Interface 的方式,我們可以在 MainActivity 中更有條理的控管我們的程式碼。
另外透過自行宣告一個 BackHandledFragment,我們可以於 MainActivity 中控管每個 Fragment 的 onBackPressed 所執行的動作。
《實作方法》
以下透過片段程式碼的方式,說明如何利用 Interface 於 MainActivity 中有效控管 Fragment 與 onBackPressed。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package com.fuhu.nabipass.fragment; import android.os.Bundle; import android.support.v4.app.Fragment; public abstract class BackHandledFragment extends Fragment { protected BackHandlerInterface backHandlerInterface; public abstract String getTagText(); public abstract boolean onBackPressedFlag(); public interface BackHandlerInterface { public void setSelectedFragment(BackHandledFragment backHandledFragment); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(!(getActivity() instanceof BackHandlerInterface)) { throw new ClassCastException("Hosting activity must implement BackHandlerInterface"); } else { backHandlerInterface = (BackHandlerInterface) getActivity(); } } @Override public void onStart() { super.onStart(); // Mark this fragment as the selected Fragment. backHandlerInterface.setSelectedFragment(this); } } |
BackHandledFragment.java
宣告一個自訂虛擬類別 BackHandledFragment,在裡面定義一個自訂介面 BackHandlerInterface,並宣告一個實作(implements)這個介面的物件 backHandlerInterface,透過這個物件,我們可以控管所有有繼承 BackHandledFragment 類別的 Fragment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
import com.fragment.BackHandledFragment; import com.fragment.BackHandledFragment.BackHandlerInterface; import com.fragment.Fragment01.ViewStatus_Fragment01; import com.fragment.Fragment02.ViewStatus_Fragment02; import com.fragment.Fragment03.ViewStatus_Fragment03; import com.fragment.Fragment04.ViewStatus_Fragment04; . . . public class MainActivity extends FragmentActivity implements BackHandlerInterface, Fragment01.CallbackInterface, Fragment02.CallbackInterface, Fragment03.CallbackInterface, Fragment04.CallbackInterface { public FragmentManager mFragMgr; public FragmentTransaction mFragTran; private BackHandledFragment selectedFragment; @Override public void setSelectedFragment(BackHandledFragment backHandledFragment) { // TODO Auto-generated method stub this.selectedFragment = backHandledFragment; } @Override public void onBackPressed() { if(selectedFragment == null || selectedFragment.onBackPressedFlag())//check if the onBackPressedFlag is true or false to manage fragments' backPressed { super.onBackPressed(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_startfreemonth); mFragMgr = getSupportFragmentManager(); switchFragment(new OnePassForEverythingFragment()); } @Override public void updateContentView_By_Fragment01(ViewStatus_Fragment01 status) { // TODO Auto-generated method stub if(status == ViewStatus_Fragment01.Action01) { switchFragment(new Fragment02()); } else if((status == ViewStatus_Fragment01.Action02)) { switchFragment(new Fragment03()); } } @Override public void updateContentView_By_Fragment02(ViewStatus_Fragment02 status, Fragment02 frag) {...} @Override public void updateContentView_By_Fragment03(ViewStatus_Fragment03 status, Fragment03 frag) {...} @Override public void updateContentView_By_Fragment04(ViewStatus_Fragment04 status, Fragment04 frag) {...} public void switchFragment(Fragment frag) { String sFragTag; mFragTran = mFragMgr.beginTransaction(); mTagCount++; sFragTag = TAG + new Integer(mTagCount).toString(); mFragTran.replace(R.id.rootParent, frag, sFragTag); mFragTran.addToBackStack(null); mFragTran.commit(); } } |
MainActivity.java
在這個例子中,我們首先自行定義了四個 Fragment,分別為 Fragment01、Fragment02、Fragment03、Fragment04,這四個 Fragment 皆繼承了 BackHandledFragment 這個虛擬類別,因此每個 Fragment 皆必須覆寫 getTagText() 以及 onBackPressedFlag() 這兩個方法,從這邊我們可以透過 onBackPressedFlag() 這個方法回傳 true 或 false,控管我們的 onBackPressed 動作。
另外在這四個 Fragment 中,我們皆在其中定義了一個名稱為 CallbackInterface 的介面,透過在這個介面中建構所需的方法,我們可以在建構好方法框架後,於 MainActivity 中實作並重新定義於介面中建構好的方法,藉此達到控管 Fragment 的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
import com.fragment.BackHandledFragment; . . . public class Fragment01 extends BackHandledFragment { private Button btn_Action01, btn_Action02; private CallbackInterface mCallback; public interface CallbackInterface { public void updateContentView_By_Fragment01(ViewStatus_Fragment01 status); }; public enum ViewStatus_Fragment01 { Action01, Action02; } @Override public void onAttach(Activity activity) { super.onAttach(activity); try {mCallback = (CallbackInterface) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString() + "must implement Fragment01.CallbackInterface.");} } @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.one_pass_for_everything_fragment, container, false); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setupViewComponent(); } public void setupViewComponent() { btn_Action01 = (Button)getView().findViewById(R.id.btn_Action01); btn_Action02 = (Button)getView().findViewById(R.id.btn_Action02); btn_Action01.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCallback.updateContentView_By_Fragment01(ViewStatus_Fragment01.Action01); } }); btn_Action02.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mCallback.updateContentView_By_Fragment01(ViewStatus_Fragment01.Action02); } }); } @Override public String getTagText() { return (String) this.getTag(); } @Override public boolean onBackPressedFlag() { return false; } } |
Fragment01.java
我們自訂了一個繼承 BackHandledFragment 的 Fragment 類別(Fragment01),並在其中宣告了名為 CallbackInterface 的介面,此介面包含了一個定義好的方法架構叫做 updateContentView_By_Fragment01(ViewStatus_Fragment01 status),這個方法架構目前內容是空的,因此我們在 MainActivity 中透過實作(implements)的方式,在這些尚未定義內容的方法框架裡實作我們需要的動作,也就是切換 Fragment 這個動作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import com.fragment.BackHandledFragment; . . . public class Fragment0X extends BackHandledFragment { ... private CallbackInterface mCallback; public interface CallbackInterface { public void updateContentView_By_Fragment0X(ViewStatus_Fragment0X status); }; public enum ViewStatus_Fragment0X { Action01, Action02, Action03...; } @Override public void onAttach(Activity activity) { super.onAttach(activity); try {mCallback = (CallbackInterface) activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString() + "must implement Fragment0X.CallbackInterface.");} } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment0X, container, false); return rootView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setupViewComponent(); } public void setupViewComponent() { ... mCallback.updateContentView_By_Fragment0X(ViewStatus_Fragment0X.Action0X); ... } @Override public String getTagText() { return (String) this.getTag(); } @Override public boolean onBackPressedFlag() { return false; } } |
Fragment02、Fragment03、Fragment04
在此範例中,我們於 MainActivity 中實作了 updateContentView_By_Fragment01()、updateContentView_By_Fragment02()、 updateContentView_By_Fragment03()、updateContentView_By_Fragment04()四種方法, 這四種方法分別是四個 Fragment 中定義的介面(CallbackInterface )所建構的方法框架。
透過這種方式,所有的 Fragment 之間的切換就可以都在 MainActivity 中執行,另外其實當中的 CallbackInterface 介面,亦可以像 BackHandledFragment 一樣獨立出來宣告,如此一來程式碼可以更為清楚與精簡。
臉書留言
一般留言