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);
}
}
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);
}
}