Android Fragment 之间的通讯处理

上集回顾

上一次已经有结果了,有三种通讯方式
文章连接:Click Me

1.使用接口,让Activity扮演管理角色,负责分发消息到该窗口的子View

2.使用LocalBroadcastManager + IntentFilter解决不同组件通讯,Intent负责搭载数据

3.EventBus

4.otto 这里不做介绍,下面有demo链接,基于注解的解偶通信组件

其实按照MVC的思想,Activity就真正的变成了Controler,
Activity中不涉及任何的业务逻辑的代码,只负责分发消息到不同的子View(Fragment)。
如果希望整个应用只有一个Activity,就需要再抽象出一层Controller,负责处理Activity与其子Controller的通讯

相关下载

项目

我们直接看代码吧,因为表达能力还训练,加上有点懒 ^_^ 😄
项目结构
###首先是布局de代码 - /layout/article_view.xml ** ArticleFragment.java ** 关联的布局

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/article"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:textSize="18sp" >
</TextView>
  • /layout/news_articles.xml ** HeadlinesFragment.java ** 关联的布局
1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</FrameLayout>
  • /layout-large/new_articles.xml ** HeadlinesFragment.java ** 关联的布局,在平板大分辨率的时候回被自动启用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/headlines_fragment"
        android:name="tree.love.android.fragments.HeadlinesFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/article_fragment"
        android:name="tree.love.android.fragments.ArticleFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2" />

</LinearLayout>
  • MainActivity.java 首页 -_- 其实就那么一页 哈哈哈
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
public class MainActivity extends FragmentActivity  implements HeadlinesFragment.OnHeadlineSelectedListener {
	
	private static final String TAG = "MainActivity";

	private LocalBroadcastManager mBroadcastManager;
	private BroadcastReceiver mItemViewListClickReceiver;
	
	public static final String ACTION_ITEMVIEW_LISTCLICK = "tree.love.android.fragments.itemview.listclick";
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_articles);
        //如果是手机分辨率布局
        if (findViewById(R.id.fragment_container) != null) {

        	// 如果之前保存了状态,我们不需要做任何事情,否则会重复加载Fragment
            if (savedInstanceState != null) {
                return;
            }
            // Create an instance of ExampleFragment
            HeadlinesFragment firstFragment = new HeadlinesFragment();

            //如果这个Activity被一个特殊的Intent传递,如果有需要,把该数据也传给Fragment
            firstFragment.setArguments(getIntent().getExtras());

            // 添加该Fragment到R.id.fragment_container这个容器布局中
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, firstFragment).commit();
        }
    }

	private void initBroadcastListener() {
		mBroadcastManager = LocalBroadcastManager.getInstance(this);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_ITEMVIEW_LISTCLICK);
        mItemViewListClickReceiver = new BroadcastReceiver()
		{
			@Override
			public void onReceive(Context context, Intent intent)
			{
				if(intent.getAction().equals(ACTION_ITEMVIEW_LISTCLICK))
				{
					Log.v(TAG, ACTION_ITEMVIEW_LISTCLICK + "," + intent.getIntExtra("position", -1));
				}
			}
		};
        mBroadcastManager.registerReceiver(mItemViewListClickReceiver, intentFilter);
	}

    /* 
     * 实现HeadlinesFragment.OnHeadlineSelectedListener中的ListView点击事件的回调接口
     */
    public void onArticleSelected(int position) {

        // 获取当前Activity是否已经加载了ArticleFragment
        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);

        if (articleFrag != null) {
        	//如果进到这里,说明我们正在使用大屏幕布局/.
        	//直接更新ArticleFragment的布局
            articleFrag.updateArticleView(position);

        } else {
            // 我们正在使用小屏幕布局
            // 创建Fragment,并且传递参数
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            //可定制Fragment的退出和进入动画 , 设置在replace or add之前
            transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out, android.R.anim.fade_in, android.R.anim.fade_out);

            // 替换R.id.fragment_container容器布局中的View
            transaction.replace(R.id.fragment_container, newFragment);

            // 添加事物回退栈,让系统管理,当用户点击返回按钮时,销毁当前加载到容器布局中的ArticleFragment
            transaction.addToBackStack(null);

            // 提交事物...不然你永远看不到ArticleFragment的出现 ^_^
            transaction.commit();
        }
    }

    /**
     * EventBus事件回掉
     * @param event
     */
    public void onEvent(ListClickEvent event)
    {
    	Log.v("", "onEvent position:" + event.getPosition());
    }

    @Override
    protected void onStart() {
    	super.onStart();
    	//在需要接收事件通知的类添加到EventBus
        EventBus.getDefault().register(this);
        //注册Receiver
        initBroadcastListener();
    }

    @Override
    protected void onPause()
    {
    	super.onPause();
    	//取消事件监听
    	EventBus.getDefault().unregister(this);
    	mBroadcastManager.unregisterReceiver(mItemViewListClickReceiver);
    }
}
  • HeadlinesFragment.java ListView菜单布局
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
 public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // 通讯接口, 加载该Fragment的容器Activity必须实现此接口可以接收ListView的点击消息
    public interface OnHeadlineSelectedListener {
        /** 当HeadlinesFragment中的ListView点击的时候触发 */
        public void onArticleSelected(int position);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;
        setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));
    }

    @Override
    public void onStart() {
        super.onStart();

        if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) {
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // 保证容器Activity实现了回调接口 否则抛出异常警告
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()  + " must implement OnHeadlineSelectedListener");
        }
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        //1.通讯方式1  接口通知Activity
        mCallback.onArticleSelected(position);

        //2.通讯方式2  发送广播
        Intent intent = new Intent(MainActivity.ACTION_ITEMVIEW_LISTCLICK);
        intent.putExtra("position", position);
        LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent);

        //3.通讯方式3  发送事件到消息中心,由消息中心负责分发事件
        EventBus.getDefault().post(new ListClickEvent(position));

        // 大屏幕pad分辨率使用两个panel的时候设置
        getListView().setItemChecked(position, true);
    }
}
  • ArticleFragment.java 详情页布局。。就一个TextView啦。
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
 public class ArticleFragment extends Fragment {
	
    final static String ARG_POSITION = "position";
    int mCurrentPosition = -1;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    	//回复在onSaveInstanceState中保存的是状态数据
        if (savedInstanceState != null) {
            mCurrentPosition = savedInstanceState.getInt(ARG_POSITION);
        }

        return inflater.inflate(R.layout.article_view, container, false);
    }

    @Override
    public void onStart() {
        super.onStart();

        Bundle args = getArguments();
        if (args != null) {
            updateArticleView(args.getInt(ARG_POSITION));
        } else if (mCurrentPosition != -1) {
            updateArticleView(mCurrentPosition);
        }

        EventBus.getDefault().register(this);
    }

    @Override
    public void onPause()
    {
    	super.onPause();
    	EventBus.getDefault().unregister(this);
    }

    public void updateArticleView(int position) {
        TextView article = (TextView) getActivity().findViewById(R.id.article);
        article.setText(Ipsum.Articles[position]);
        mCurrentPosition = position;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(ARG_POSITION, mCurrentPosition);
    }

    public void onEvent(ListClickEvent event)
    {
    	Log.v("ArticleFragment", "onEvent" + event.getPosition());
    }
}