介面實現Fragment、Activity間互調解耦
fragment之間及Fragment與Activity互調在實際應用中極為常見,比如官方API介紹Fragment給出的平板新聞客戶端例子,UI左邊是標題Fragment,UI右邊是內容Fragment,點選不同的標題,顯示不同的新聞內容,這是一個簡單的Fragment間互調。根據Fragment互調是否解耦,是否貫徹面向物件程式設計思想,可以分為野路子做法及正規軍做法,當然二者都能實現目的。本文通過具體的實現及改進過程,逐步降低Fragment互調的耦合度。
一、野路子用法
1、Fragment/Activity---呼叫--->Fragment
每個Fragment都有一個唯一的TAG或者ID,可以通過getFragmentManager.findFragmentByTag(),或者findFragmentById()獲得任何Fragment例項,然後進行操作。
2、Fragment--呼叫-->Activity
通過getActivity得到當前繫結的Activity的例項,然後進行操作。
上面兩種程式設計思想一目瞭然,在程式設計中也極為常見,具體到新聞客戶端例子,就是在TitleFragment中通過程式碼直接呼叫ContentFragment,這樣做TitleFragment就與ContentFragment高度耦合,TitleFragment程式碼被寫死,直接破壞Fragment的重用思想。
下面是應用傳統野路子實現過程:
ContentFragment.java
public class ContentFragment extends Fragment { String[] news = new String[]{ "日企員工如何跟老闆請假9.3日", "手撕鬼子", "9月9日憶山東兄弟", }; private int dataId; private TextView tv; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { tv = new TextView(getActivity()); Bundle bundle = getArguments(); dataId = bundle.getInt("dataId"); tv.setText(news[dataId]); return tv; } public void setData(int dataId){ this.dataId = dataId; tv.setText(news[dataId]); } }
TitleFragment.java
public class TitleFragment extends ListFragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); //初始化資料 ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, data); setListAdapter(adapter); fm = getFragmentManager(); getListView().setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //顯示contentFragment //傳資料給ContentFragment,修改那邊的結果 f = fm.findFragmentByTag("content"); if(f == null){ //先建立ContentFragment,然後新增到佈局裡面。 FragmentTransaction ft = fm.beginTransaction(); f = new ContentFragment(); //給fragment如何賦初始值 Bundle bundle = new Bundle(); bundle.putInt("dataId",0); f.setArguments(bundle); ft.add(R.id.fg_content, f, "content"); ft.commit(); }else{ ContentFragment cf = (ContentFragment) f; f.getArguments().putInt("dataId",position);//獲取bundle } }
二、正規軍用法:
Fragment互調使用介面通訊。考慮Fragment的重用,所以必須降低Fragment與Activity的耦合,而且Fragment更不應該直接操作別的Fragment,畢竟Fragment操作應該由它的管理者Activity來決定。
改進一:
TitleItemClickListener.java
public interface TitleItemClickListener {
void onItemClick(int position );
}
</pre><pre code_snippet_id="1587149" snippet_file_name="blog_20160224_7_886404" name="code" class="html">MainActivity.java
public class MainActivity extends Activity implements TitleItemClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getFragmentManager();
TitleFragment tf = (TitleFragment) fm.findFragmentById(R.id.fg_title);
}
public void setNewsTitle(int position){
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText("鬼子"+position);
}
@Override
public void onItemClick(int position) {
setNewsTitle(position);
}
}
TitleFragment.java
public class TitleFragment extends ListFragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//初始化資料
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, data);
setListAdapter(adapter);
fm = getFragmentManager();
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
TitleItemClickListener listener = (TitleItemClickListener) getActivity();
listener.onItemClick(position);
}
}
Fragment之間通過Activity通訊,降低了耦合性,但TitleFragment的重用性有待加強,因為TitleFragment的程式碼: TitleItemClickListener listener = (TitleItemClickListener) getActivity();
這段程式碼涉及到getActivity(),所以只能被Activity重用,這是一個限制,所以可以進一步改進。
改進二:
TitleFragment.java
public class TitleFragment extends ListFragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//初始化資料
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, data);
setListAdapter(adapter);
fm = getFragmentManager();
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
listener.onItemClick(position);
}
public void setTitleItemClickListener(TitleItemClickListener listener){
this.listener = listener;
}
}
MainActivity.java
public class MainActivity extends Activity implements TitleItemClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fm = getFragmentManager();
TitleFragment tf = (TitleFragment) fm.findFragmentById(R.id.fg_title);
tf.setTitleItemClickListener(this);
}
public void setNewsTitle(int position){
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText("鬼子"+position);
}
@Override
public void onItemClick(int position) {
setNewsTitle(position);
}
}
至此,耦合完全解除。