Android Fragment之间的通讯处理

移动开发 Android
Fragment是google由3.0开始加入SDK的界面解决方案,后续由谷歌团队维护并发行了support包以支持低版本SDK来使用Fragment。本文重点介绍了如何解决模块之间的通讯的耦合问题。

Fragment是google由3.0开始加入SDK的界面解决方案。

后续由谷歌团队维护并发行了support包以支持低版本SDK来使用Fragment。

谁在使用Fragment

  • 网易新闻
  • 网易云音乐
  • 百度音乐
  • 多米
  • 豌豆荚
  • 小米app
  • Path
  • Pocket
  • Fuubo

###Fragment的优点 —————- * adding and removing Fragment可以做动画的效果,平滑过度

  • 自动化堆栈管理,所以返回键可以删除动态添加的Fragment,***销毁Activity,无需做过多判断

  • 集成ActionBar的标签,可以替代TabHost,ActivityGrounp,与谷歌设计风格紧密结合

  • 布局更加模块化.与原Activity中的Layout分块化,VCBase的分块化道理相同

  • 灵活准确的生命周期去管理当前View的状态记录以及横竖屏处理

  • Fragment管理的View,可同时使用在Phone和Pad上,一份代码两份机器,可重用性高

  • Is a View, More than View

  • 可以从startActivityForResult中接收到返回结果,但是View不能

  • 唯一Id标识,可以从FragmentManager中获取id对应的Fragment

Fragment的缺点

与其说是Fragment的缺点,不如说是每个应用程序模块之间的通讯都面临地耦合问题

  • Fragment之间的通讯依赖Activity使用接口管理并通知

如何解决模块之间的通讯的耦合问题

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

该方案的缺点

  • 不方便使用单元测试
  • 随着应用功能的增加,需要监听的事件越来越多,导致越来越多的接口声明以及绑定

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

该方案的缺点

  • 不方便单元测试,需要实例化Intent,填装Intent的数据,实现Broadcast receivers以及再次提取Intent中的数据
  • receiver中不可做耗时操作,因为reciver是限时进程,10秒后会被系统kill掉,如果需要做耗时操作,需另外启Service来完成

3.EventBus

  • 消息订阅者:Activity or Fragment等订阅类注册自己到EventBus中
  • 消息发布者:只负责发布消息以及消息包装数据到EventBus
  • 回调基于命名约定以及消息包装对象
  • 方便的单元测试

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

其实按照MVC的思想,Activity就真正的变成了Controler,

Activity中不涉及任何的业务逻辑的代码,只负责分发消息到不同的子View(Fragment)。

如果希望整个应用只有一个Activity,就需要再抽象出一层Controller,负责处理Activity与其子Controller的通讯

相关下载

项目

我们直接看代码吧,因为表达能力还训练,加上有点懒 ^_^ 😄

项目结构

###首先是布局de代码 - /layout/article_view.xml ** ArticleFragment.java ** 关联的布局

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <TextView xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:id="@+id/article" 
  4.     android:layout_width="match_parent" 
  5.     android:layout_height="match_parent" 
  6.     android:padding="16dp" 
  7.     android:textSize="18sp" > 
  8. </TextView> 

/layout/news_articles.xml ** HeadlinesFragment.java ** 关联的布局

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:id="@+id/fragment_container" 
  4.     android:layout_width="match_parent" 
  5.     android:layout_height="match_parent" > 
  6. </FrameLayout> 

/layout-large/new_articles.xml ** HeadlinesFragment.java ** 关联的布局,在平板大分辨率的时候回被自动启用

  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="horizontal" > 
  6.  
  7.     <fragment 
  8.         android:id="@+id/headlines_fragment" 
  9.         android:name="tree.love.android.fragments.HeadlinesFragment" 
  10.         android:layout_width="0dp" 
  11.         android:layout_height="match_parent" 
  12.         android:layout_weight="1" /> 
  13.  
  14.     <fragment 
  15.         android:id="@+id/article_fragment" 
  16.         android:name="tree.love.android.fragments.ArticleFragment" 
  17.         android:layout_width="0dp" 
  18.         android:layout_height="match_parent" 
  19.         android:layout_weight="2" /> 
  20.  
  21. </LinearLayout> 

#p#

MainActivity.java 首页 -_- 其实就那么一页 哈哈哈

  1. public class MainActivity extends FragmentActivity  implements HeadlinesFragment.OnHeadlineSelectedListener { 
  2.      
  3.     private static final String TAG = "MainActivity"
  4.  
  5.     private LocalBroadcastManager mBroadcastManager; 
  6.     private BroadcastReceiver mItemViewListClickReceiver; 
  7.      
  8.     public static final String ACTION_ITEMVIEW_LISTCLICK = "tree.love.android.fragments.itemview.listclick"
  9.      
  10.     @Override 
  11.     public void onCreate(Bundle savedInstanceState) { 
  12.         super.onCreate(savedInstanceState); 
  13.         setContentView(R.layout.news_articles); 
  14.         //如果是手机分辨率布局 
  15.         if (findViewById(R.id.fragment_container) != null) { 
  16.  
  17.             // 如果之前保存了状态,我们不需要做任何事情,否则会重复加载Fragment 
  18.             if (savedInstanceState != null) { 
  19.                 return
  20.             } 
  21.             // Create an instance of ExampleFragment 
  22.             HeadlinesFragment firstFragment = new HeadlinesFragment(); 
  23.  
  24.             //如果这个Activity被一个特殊的Intent传递,如果有需要,把该数据也传给Fragment 
  25.             firstFragment.setArguments(getIntent().getExtras()); 
  26.  
  27.             // 添加该Fragment到R.id.fragment_container这个容器布局中 
  28.             getSupportFragmentManager().beginTransaction() 
  29.                     .add(R.id.fragment_container, firstFragment).commit(); 
  30.         } 
  31.     } 
  32.  
  33.     private void initBroadcastListener() { 
  34.         mBroadcastManager = LocalBroadcastManager.getInstance(this); 
  35.         IntentFilter intentFilter = new IntentFilter(); 
  36.         intentFilter.addAction(ACTION_ITEMVIEW_LISTCLICK); 
  37.         mItemViewListClickReceiver = new BroadcastReceiver() 
  38.         { 
  39.             @Override 
  40.             public void onReceive(Context context, Intent intent) 
  41.             { 
  42.                 if(intent.getAction().equals(ACTION_ITEMVIEW_LISTCLICK)) 
  43.                 { 
  44.                     Log.v(TAG, ACTION_ITEMVIEW_LISTCLICK + "," + intent.getIntExtra("position", -1)); 
  45.                 } 
  46.             } 
  47.         }; 
  48.         mBroadcastManager.registerReceiver(mItemViewListClickReceiver, intentFilter); 
  49.     } 
  50.  
  51.     /*  
  52.      * 实现HeadlinesFragment.OnHeadlineSelectedListener中的ListView点击事件的回调接口 
  53.      */ 
  54.     public void onArticleSelected(int position) { 
  55.  
  56.         // 获取当前Activity是否已经加载了ArticleFragment 
  57.         ArticleFragment articleFrag = (ArticleFragment) 
  58.                 getSupportFragmentManager().findFragmentById(R.id.article_fragment); 
  59.  
  60.         if (articleFrag != null) { 
  61.             //如果进到这里,说明我们正在使用大屏幕布局/. 
  62.             //直接更新ArticleFragment的布局 
  63.             articleFrag.updateArticleView(position); 
  64.  
  65.         } else { 
  66.             // 我们正在使用小屏幕布局 
  67.             // 创建Fragment,并且传递参数 
  68.             ArticleFragment newFragment = new ArticleFragment(); 
  69.             Bundle args = new Bundle(); 
  70.             args.putInt(ArticleFragment.ARG_POSITION, position); 
  71.             newFragment.setArguments(args); 
  72.             FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 
  73.  
  74.             //可定制Fragment的退出和进入动画 , 设置在replace or add之前 
  75.             transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out, android.R.anim.fade_in, android.R.anim.fade_out); 
  76.  
  77.             // 替换R.id.fragment_container容器布局中的View 
  78.             transaction.replace(R.id.fragment_container, newFragment); 
  79.  
  80.             // 添加事物回退栈,让系统管理,当用户点击返回按钮时,销毁当前加载到容器布局中的ArticleFragment 
  81.             transaction.addToBackStack(null); 
  82.  
  83.             // 提交事物...不然你永远看不到ArticleFragment的出现 ^_^ 
  84.             transaction.commit(); 
  85.         } 
  86.     } 
  87.  
  88.     /** 
  89.      * EventBus事件回掉 
  90.      * @param event 
  91.      */ 
  92.     public void onEvent(ListClickEvent event) 
  93.     { 
  94.         Log.v("""onEvent position:" + event.getPosition()); 
  95.     } 
  96.  
  97.     @Override 
  98.     protected void onStart() { 
  99.         super.onStart(); 
  100.         //在需要接收事件通知的类添加到EventBus 
  101.         EventBus.getDefault().register(this); 
  102.         //注册Receiver 
  103.         initBroadcastListener(); 
  104.     } 
  105.  
  106.     @Override 
  107.     protected void onPause() 
  108.     { 
  109.         super.onPause(); 
  110.         //取消事件监听 
  111.         EventBus.getDefault().unregister(this); 
  112.         mBroadcastManager.unregisterReceiver(mItemViewListClickReceiver); 
  113.     } 

HeadlinesFragment.java ListView菜单布局

  1. public class HeadlinesFragment extends ListFragment { 
  2.     OnHeadlineSelectedListener mCallback; 
  3.  
  4.     // 通讯接口, 加载该Fragment的容器Activity必须实现此接口可以接收ListView的点击消息 
  5.     public interface OnHeadlineSelectedListener { 
  6.         /** 当HeadlinesFragment中的ListView点击的时候触发 */ 
  7.         public void onArticleSelected(int position); 
  8.     } 
  9.  
  10.     @Override 
  11.     public void onCreate(Bundle savedInstanceState) { 
  12.         super.onCreate(savedInstanceState); 
  13.  
  14.         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; 
  15.         setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines)); 
  16.     } 
  17.  
  18.     @Override 
  19.     public void onStart() { 
  20.         super.onStart(); 
  21.  
  22.         if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) { 
  23.             getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); 
  24.         } 
  25.     } 
  26.  
  27.     @Override 
  28.     public void onAttach(Activity activity) { 
  29.         super.onAttach(activity); 
  30.  
  31.         // 保证容器Activity实现了回调接口 否则抛出异常警告 
  32.         try { 
  33.             mCallback = (OnHeadlineSelectedListener) activity; 
  34.         } catch (ClassCastException e) { 
  35.             throw new ClassCastException(activity.toString()  + " must implement OnHeadlineSelectedListener"); 
  36.         } 
  37.     } 
  38.  
  39.     @Override 
  40.     public void onListItemClick(ListView l, View v, int position, long id) { 
  41.         //1.通讯方式1  接口通知Activity 
  42.         mCallback.onArticleSelected(position); 
  43.  
  44.         //2.通讯方式2  发送广播 
  45.         Intent intent = new Intent(MainActivity.ACTION_ITEMVIEW_LISTCLICK); 
  46.         intent.putExtra("position", position); 
  47.         LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(intent); 
  48.  
  49.         //3.通讯方式3  发送事件到消息中心,由消息中心负责分发事件 
  50.         EventBus.getDefault().post(new ListClickEvent(position)); 
  51.  
  52.         // 大屏幕pad分辨率使用两个panel的时候设置 
  53.         getListView().setItemChecked(position, true); 
  54.     } 

ArticleFragment.java 详情页布局。。就一个TextView啦。

  1. public class ArticleFragment extends Fragment { 
  2.  
  3.    final static String ARG_POSITION = "position"
  4.    int mCurrentPosition = -1
  5.  
  6.    @Override 
  7.    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
  8.        Bundle savedInstanceState) { 
  9.  
  10.     //回复在onSaveInstanceState中保存的是状态数据 
  11.        if (savedInstanceState != null) { 
  12.            mCurrentPosition = savedInstanceState.getInt(ARG_POSITION); 
  13.        } 
  14.  
  15.        return inflater.inflate(R.layout.article_view, container, false); 
  16.    } 
  17.  
  18.    @Override 
  19.    public void onStart() { 
  20.        super.onStart(); 
  21.  
  22.        Bundle args = getArguments(); 
  23.        if (args != null) { 
  24.            updateArticleView(args.getInt(ARG_POSITION)); 
  25.        } else if (mCurrentPosition != -1) { 
  26.            updateArticleView(mCurrentPosition); 
  27.        } 
  28.  
  29.        EventBus.getDefault().register(this); 
  30.    } 
  31.  
  32.    @Override 
  33.    public void onPause() 
  34.    { 
  35.     super.onPause(); 
  36.     EventBus.getDefault().unregister(this); 
  37.    } 
  38.  
  39.    public void updateArticleView(int position) { 
  40.        TextView article = (TextView) getActivity().findViewById(R.id.article); 
  41.        article.setText(Ipsum.Articles[position]); 
  42.        mCurrentPosition = position; 
  43.    } 
  44.  
  45.    @Override 
  46.    public void onSaveInstanceState(Bundle outState) { 
  47.        super.onSaveInstanceState(outState); 
  48.        outState.putInt(ARG_POSITION, mCurrentPosition); 
  49.    } 
  50.  
  51.    public void onEvent(ListClickEvent event) 
  52.    { 
  53.     Log.v("ArticleFragment""onEvent" + event.getPosition()); 
  54.    } 

原文地址:http://wuyexiong.github.io/blog/2013/04/30/android-fragment-communication/

责任编辑:闫佳明 来源: wuyexiong.github.io
相关推荐

2010-04-22 17:19:49

负载均衡群集通讯

2010-04-22 17:32:21

负载均衡通讯

2023-06-27 07:31:59

微服务容错库重试

2016-12-02 19:00:13

Android FraAndroid

2013-07-10 15:52:17

fragmentAndroid

2013-06-04 17:23:55

Android开发移动开发Fragment

2014-07-29 09:16:14

Fragment

2023-02-03 17:28:44

HIDLAndroid硬件

2014-04-16 13:31:27

AndroidFragment多屏幕支持

2009-09-01 18:16:41

C#窗体间通讯

2021-06-16 07:21:39

AndroidAndroid系统多进程通讯

2011-05-19 17:49:08

ActivityAndroid开发

2014-07-21 10:12:00

FragmentiewPagerIndcsdn app

2013-04-25 09:33:59

网络处理器路由器交换机

2010-06-18 22:42:42

智能手机平台Android网秦

2013-06-03 17:17:14

Android开发Android程序Android手机平板

2021-07-14 14:05:24

Fragment项目结构

2010-03-04 16:08:21

Android系统平台

2019-06-25 10:53:06

AndroidFlutter通信

2018-10-15 16:23:24

Android 源码开源
点赞
收藏

51CTO技术栈公众号