在使用fragment的时候,通常的用法都是使用一个activity来管理不同的fragment,所以每个fragment与activity的及时通讯就很重要。
1、Fragment可以调用getActivity()方法很容易的得到它所在的activity的对象,然后就可以查找activity中的控件们(findViewById())。例如:
Viewlist View =getActivity().findViewById(R.id.list);
同样的,activity也可以通过FragmentManager的方法查找它所包含的frament们。例如:
ExampleFragment fragment =(ExampleFragment)getFragmentManager().findFragmentById(R.id.example_fragment)
但是这个并不是最好的办法,根据fragmen的定义,我们可以在fragment里面定义一个回调接口,在activity中实现它。举个谷歌官方给的例子,这是一个新闻程序的例子,它有一个activity,activity中含有两个fragment。fragmentA显示新闻标题,fragmentB显示标题对应的内容。fragmentA必须在用户选择了某个标题时告诉activity,然后activity再告诉fragmentB,fragmentB就显示出对应的内容(为什么这么麻烦?直接fragmentA告诉fragmentB不就行了?也可以啊,但是你的fragment就减少了可重用的能力。现在我只需把我的事件告诉宿主,由宿主决定如何处置,这样是不是重用性更好呢?)。如下例:
public class PersionListFragment extends ListFragment {
private static final String STATE_ACTIVATED_POSITION = "activated_position";
private Callbacks mCallbacks = sDummyCallbacks;
private int mActivatedPosition = ListView.INVALID_POSITION;
public interface Callbacks {
public void onItemSelected(String id);
}
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
public void onItemSelected(String id) {
}
};
我们在PersionListFragment中定义了mCallbacks这个接口,当然了我们自己实现了一个空的接口内容sDummyCallbacks,当作mCallbacks的默认接口。
下面就是我们要到Activity中去实现这个接口:
public class PersionListActivity extends FragmentActivity implements PersionListFragment.Callbacks {
private boolean mTwoPane;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_persion_twopane);
if (findViewById(R.id.persion_detail_container) != null) {
mTwoPane = true;
((PersionListFragment) getSupportFragmentManager().findFragmentById(R.id.persion_list)).setActivateOnItemClick(false);
}
}
@Override
public void onItemSelected(String id) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(PersionDetailFragment.ARG_ITEM_ID, id);
PersionDetailFragment fragment = new PersionDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().replace(R.id.persion_detail_container, fragment).commit();
} else {
Intent detailIntent = new Intent(this, PersionDetailActivity.class);
detailIntent.putExtra(PersionDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
}
那么实现完了接口怎么传给刚才的fragment呢?
当fragment添加到activity中时,会调用fragment的方法onAttach(),这个方法中适合检查activity是否实现了OnArticleSelectedListener接口,检查方法就是对传入的activity的实例进行类型转换,然后赋值给我们在fragment中定义的接口。
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = sDummyCallbacks;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
}
在一个fragment从activity中剥离的时候,就会调用onDetach方法,这个时候正好可以把它的接口恢复为默认接口。防止不必要的错误。注意看onAttach方法中的代码,在赋值之前要做一个判断,看看Activity中有没有实现了这个接口,用到了instanceof。如果没有实现接口,我们就抛出异常。
这个时候我们就实现了Fragment与Activity之间的通讯,把主要的事情还是都交给管理员Activity做比较好。