多个Fragment组件可以拼接成一个Activity,那么这些Fragment如何通信呢?例如,一个显示新闻的Activity有两个Fragment,一个显示标题列表,一个显示新闻内容,点击标题列表项的时候就去更新新闻内容。为了实现Fragment的重用,Fragment之间不应该直接通信,而应该通过Activity通信。由于Fragment并不知道自己会寄生在哪个Activity,所以Fragment不知道如何向宿主Activity发送消息。那么Fragment如何与Activity通信呢?虽然Fragment不知道自己会寄生在哪个Activity下,但是Activity知道寄生在它内部的Fragment,所以可以让Activity实现一个Fragment能够识别的接口。Fragment通过接口回调,即可向其他Fragment发送消息。
下面通过一个例子展示Fragment如何与Activity通信。
新闻列表Fragment:
1. package com.zzj.ui.activityTalkWithFragmentDemo;
2.
3. import android.app.Activity;
4. import android.app.ListFragment;
5. import android.os.Bundle;
6. import android.view.View;
7. import android.widget.ArrayAdapter;
8. import android.widget.ListView;
9.
10. public class TitleListFragment extends ListFragment {
11.
12. public interface TitleClick {
13. public void onClick(int titleIndex);
14. }
15.
16. private TitleClick titleClick;
17.
18. @Override
19. public void onAttach(Activity activity) {
20. super.onAttach(activity);
21.
22. if (activity instanceof TitleClick) {
23. titleClick = (TitleClick) activity;
24. else {
25. throw new RuntimeException(
26. "TitleListFragment所在的Activity必须实现TitleClick接口!");
27. }
28. }
29.
30. @Override
31. public void onActivityCreated(Bundle savedInstanceState) {
32. super.onActivityCreated(savedInstanceState);
33. Bundle bundle = getArguments();
34. "titles");
35. new ArrayAdapter<String>(getActivity(),
36. android.R.layout.simple_list_item_1, titles));
37. }
38.
39. @Override
40. public void onListItemClick(ListView l, View v, int position, long id) {
41. titleClick.onClick(position);
42. }
43.
44. @Override
45. public void onDetach() {
46. super.onDetach();
47. null;
48. }
49.
50. }
该Fragment无需布局文件。
新闻内容Fragment:
1. package com.zzj.ui.activityTalkWithFragmentDemo;
2.
3. import android.app.Fragment;
4. import android.os.Bundle;
5. import android.view.LayoutInflater;
6. import android.view.View;
7. import android.view.ViewGroup;
8. import android.widget.TextView;
9.
10. import com.zzj.ui.R;
11.
12. public class ContentFragment extends Fragment {
13. private TextView contentView;
14.
15. @Override
16. public View onCreateView(LayoutInflater inflater, ViewGroup container,
17. Bundle savedInstanceState) {
18. View view = inflater.inflate(R.layout.news_fragment_content, container,
19. false);
20. return view;
21. }
22.
23. @Override
24. public void onActivityCreated(Bundle savedInstanceState) {
25. super.onActivityCreated(savedInstanceState);
26. contentView = (TextView) getActivity().findViewById(
27. R.id.textView_content);
28. "content"));
29. }
30.
31. /**
32. * 更新内容
33. *
34. * @param content
35. */
36. public void updateContent(String contentText) {
37. contentView.setText(contentText);
38. }
39. }
新闻内容Fragment布局文件:
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="match_parent"
4. android:layout_height="match_parent"
5. android:orientation="vertical" >
6.
7. <TextView
8. android:id="@+id/textView_content"
9. android:layout_width="wrap_content"
10. android:layout_height="wrap_content"
11. android:autoLink="web" />
12.
13. </LinearLayout>
下面的Activity组装了上面的两个Fragment,并且实现TitleListFragment.TitleClick接口:
1. package com.zzj.ui.activityTalkWithFragmentDemo;
2.
3. import android.app.Activity;
4. import android.app.FragmentTransaction;
5. import android.os.Bundle;
6.
7. import com.zzj.ui.R;
8. import com.zzj.ui.activityTalkWithFragmentDemo.TitleListFragment.TitleClick;
9.
10. public class ActivityTWFragment extends Activity implements TitleClick {
11.
12. TitleListFragment titleList;
13. ContentFragment content;
14. new String[] { "阿里上市", "百度直达号", "腾讯企业号" };
15. new String[] { "http://www.alibaba.com",
16. "http://www.baidu.com", "http://www.qq.com" };
17.
18. @Override
19. protected void onCreate(Bundle savedInstanceState) {
20. super.onCreate(savedInstanceState);
21. setContentView(R.layout.activity_talkwith_fragment);
22.
23. FragmentTransaction transaction = getFragmentManager()
24. .beginTransaction();
25.
26. titleList = (TitleListFragment) getFragmentManager().findFragmentByTag(
27. "title");
28. if (titleList == null) {
29. new TitleListFragment();
30. new Bundle();
31. "titles", titles);
32. // This can only be called before the fragment has been attached to
33. // its activity
34. titleList.setArguments(bundle);
35. "title");
36. }
37. content = (ContentFragment) getFragmentManager().findFragmentByTag(
38. "content");
39. if (content == null) {
40. new ContentFragment();
41. // 初始化显示第一条内容
42. new Bundle();
43. "content", "http://www.alibaba.com");
44. content.setArguments(args);
45. "content");
46. }
47. transaction.commit();
48. }
49.
50. @Override
51. public void onClick(int titleIndex) {
52. content.updateContent(contents[titleIndex]);
53. }
54. }
Activity布局文件:
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="match_parent"
4. android:layout_height="match_parent"
5. android:baselineAligned="false"
6. android:orientation="horizontal" >
7.
8. <FrameLayout
9. android:id="@+id/title_list"
10. android:layout_width="0dp"
11. android:layout_height="match_parent"
12. android:layout_weight="1" >
13. </FrameLayout>
14.
15. <FrameLayout
16. android:id="@+id/content"
17. android:layout_width="0dp"
18. android:layout_height="match_parent"
19. android:layout_weight="2" >
20. </FrameLayout>
21.
22. </LinearLayout>
效果:
温馨提示:
1.可以在Fragment中定义一些业务方法,以更好地实现重用。例子中显示新闻内容的Fragment定义了一个更新内容的方法,这样就不必在Activity中去查找显示新闻内容的TextView组件。
2.如果要向Fragment传递参数,可以调用Fragment的setArguments(Bundle args)方法,该方法必须在调用onAttach(Activity activity)方法之前调用。