今天查看 Fragment 的官方文档,发现2点值得细究的地方:

  • Fragment 和 DetailActivity 均被定义为 static,而非定义在单独 .java 文件中;
  • Activity 和 Fragment 之间以及 Fragment 和 Fragment 之间的通信方法;

关于第1点,参见另一篇博文《雪习新知识:一张图看懂 Java 内部类》。
本文探讨第2点,感觉这是一种好的设计思想。

1. 原理

官方示例中,MainActivity 里面有2个Fragment:

  • 左边的是文章标题列表 TitleFragment;
  • 右边的是文章正文 DetailFragment;

TitleFragment 有成员类 OnArticleSelectedListener 接口,MainActivity 实现该接口,在 TitleFragment 绑定 MainActivity 时让接口指向 MainActivity,TitleFragment 处理点击事件时调用接口的方法,结果就调用 MainActivity 实现接口的方法了,在MainActivity 实现接口的方法接收数据,或接着传递给 DetailFragment 等。


UML 类图

在 MemberClass 的构造方法中实现:

public MemberClass(Host host) {mListener = (OnClickListener)host;
}

这样,MemberClass 中存在 Host 的引用 mListener,父类类型的 mListener 指向其子类 Host 的对象(其实这就是多态,在运行时自动调用子类实现的方法 onClick()),从而实现调用 Host 中的成员变量和方法,完成通信。

public class MainActivity extends Activity implements TitlesFragment.OnArticleSelectedListener {···@Overridepublic void onArticleSelected(Uri aticleUri) {}public static class TitlesFragment extends ListFragment {OnArticleSelectedListener mListener;···@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);mListener = (OnArticleSelectedListener) activity;}@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);mListener.onArticleSelected(noteUri);}public interface OnArticleSelectedListener {public void onArticleSelected(Uri aticleUri);}···}
}

2. 变形

Host 不再实现接口,而在 MemberClass 中增加 setOnClickListener(OnClickListener click); 方法,该方法在 Host 中调用,同样可以使用 Host 中成员变量和方法。

3. 应用

我们应用上面的思想来实现类似大众点评APP底部的标签切换效果,大众点评APP底部的标签如下图。

我们要实现的实际效果如下:

4. 回归

对于第2节提到的变形的方式,感觉好熟悉,翻看之前自己写的代码,恍然大悟:在可点击的按钮上添加监听事件不都是这种方式吗?!

关键点在 SDK 的 View.java 源码:

public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {public OnClickListener mListener;···public void onKeyUp(int keyCode, KeyEvent event) {···return performClick();···}public boolean performClick() {···li.mOnClickListener.onClick(this);···}public interface OnClickListener() {void onClick(View v);}public void setOnClickListener(OnClickListener l) {if (!isClickable()) {setClickable(true);}getListenerInfo().mOnClickListener = l;}···
}

当点击事件的最后一个动作“KeyUp”发生时,调用 OnClickListener.onClick(),即触发监听事件。

Button 等控件继承了 View 的 interface OnClickListener 、mOnClickListener 和 setOnClickListener() 等 public 成员,这样就与变形方式保持一致了,其中 MainActivity 是 Host,Button 是 MemberClass。两种方式核心代码对比如下:

public class MainActivity extends Activity implements View.OnClickListener{···Button btn = (Button) findViewById(R.id.btn);btn.setOnClickListener(this);@Overridepublic void onClick(View v) {···}···
}

或者是

public class MainActivity extends Activity {···Button btn = (Button) findViewById(R.id.btn);btn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {···}});···
}

4. 引申

假如 MemberClass 是一个自定义的 View,很复杂的 View,里面有很多交互事件,包括点击、长按、滑动等等,而且有些交互是要用到 Host 的成员变量。在这种情况下,MemberClass extends ViewGroup implements View.OnClickListener,在 onClick(View v) 方法中调用 Host.setXXXListener(this/new XXXListener()) 即可。

其实,Host.setXXXListener(this) (Host implements XXXListener)和 Host.setXXXListener(new XXXListener()) 是等效的,对于 Host 是透明的,在 Host 看来,MemberClass.mXXXListener.onXXX() 调用的都是在 Host 中实现的 onXXX(){},onXXX(){} 中显然是可以使用 Host 的成员变量的。

对于 Host -> MemberClass(ViewGroup),MemberClass -> View(Buton,ImageView 等),是 2 层完全相同的层级关系,以点击事件为例,事件的传递是从内到外的,view.onClick() -> MemberClass.mXXXListner.onXXX() -> Host.onXXX()

上面说的过于抽象了,举个具体的例子,以微信朋友圈的评论功能为例。

如上图,输入评论的输入框是在 Host 即Activity (当然也可能是 Fragment)中的,而评论最终是要显示在 MembClass 即 ListView 的某个 Item 中,而且输入框中出现“回复xxx”,显然“xxx”是从 Item 中传到 Activity 中的,这就是 Host 和 MemberClass 的双向通信,可以通过本文中的方法解决,具体解决方法参见 《Android 仿微信点赞和评论弹出框》。

5. 另一种通信方式

使用静态嵌套类(static nested class)进行单向通信。

在 Host 中定义静态嵌套类 AbsFragment,然后其他的 Fragment 继承该抽象类,在 AbsFragment 定义各种 getter() 方法,返回 Host 的成员变量,子 Fragment 就能获得 Host 的成员变量了。由于只能从子 Fragment 中获得 Host 的变量,故通信是单向的。

to be continued…

燕过留声:由 Activity 和 Fragment 的通信方法想到的【WIP】相关推荐

  1. 安卓APP_ Fragment(2)—— Activity与Fragment的通信

    摘自:安卓APP_ Fragment(2)-- Activity与Fragment的通信 作者:丶PURSUING 发布时间: 2021-04-16 17:23:44 网址:https://blog. ...

  2. android 小卷毛播放器,Android 音乐播放器的开发教程(四)Activity和Fragment的通信以及Fragment的切换 ----- 小达...

    Activity和Fragment的通信以及Fragment的切换 在上一篇的博客中讲到了,播放器的主界面布局,是由一个activity和一个fragment构成的,activity启动的时候,在其o ...

  3. Android:手把手教你 实现Activity 与 Fragment 相互通信(含Demo)

    https://blog.csdn.net/carson_ho/article/details/75453770 转载于:https://www.cnblogs.com/geili/p/1069967 ...

  4. android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案

    前言 最近一直在想着能否有一种更好的方案来解决:Android中Activity与Fragment之间通信的问题,什么叫更好呢,就是能让Fragment的复用性高,性能还有好(不用反射),代码还要好维 ...

  5. Lifecycle Activity和Fragment生命周期感知组件 LifecycleObserver MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. Activity与Fragment的生命周期详解

    在安卓中Activity与Fragment是非常相似的两个类,它们各自都拥有自己的生命周期,且都可以用来显示布局文件中的视图.其中Activity是通过setContenView()显示视图,而Fra ...

  7. Android Activity和Fragment的转场动画

    Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Lev ...

  8. activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...

    LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面,可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,占位图,登录失效等常 ...

  9. 多个Activity与Fragment之间的数据传递

    多个Activity与Fragment之间数据传递 问题描述 解决思路 具体解决 bug de到亲妈落泪. 问题描述 首先展示个人问题的整体框架: ActivityA:主页面,有一个PageView控 ...

  10. Android 如何快速定位当前页面是哪个Activity or Fragment

    在日常需求开发中,经常碰到不太熟悉的模块,如何快速定位相应页面对应的Activity/Fragment ? (1)查看当前Activity  :adb shell "dumpsys wind ...

最新文章

  1. flume数据丢失与重复_Flume架构及常见面试
  2. DNS and Bind (一)
  3. Nginx使用openssl生成证书文件
  4. 软件工程---第四章---形式化分析
  5. git add remote_使用git管理嵌入式软件版本
  6. MATLAB(六)数据处理
  7. 怎么修剪_幸福树怎么修剪——武汉花卉租摆
  8. js 防止重复提交方案
  9. 随想录(项目管理中的感受)
  10. python3 一年中的天数 时间转化为北京时_三年级数学《年月日》时间知识详解,帮助孩子重点知识不丢分...
  11. python可以做exe文件吗_手动制作python的exe可执行程序
  12. Windows驱动开发TraceView之日志打印
  13. 三角函数之间的转换公式
  14. UI面试常见问题总结
  15. 局域网即时通讯软件_企业即时通讯软件需要符合哪些要求?
  16. 磷脂PEG磷脂,DSPE-PEG-DSPE
  17. 苏轼:醉笑陪君三万场 不诉离殇
  18. 社工计算机技能考试考什么,社会工作者考试内容是什么?(附社工考试科目、考试教材和考试题型)...
  19. GitHub 上有什么好玩又有挑战的前端项目?
  20. 用python画国旗的程序_利用python画国旗(示例)

热门文章

  1. 模拟器桥接模式下 WLAN 无法连接及安卓 7.0+ 无法抓包 HTTPS 的解决
  2. 字体反爬-起点网月票榜案例
  3. 为什么要用深浅拷贝、什么是深浅拷贝、以及如何实现
  4. Codeforces 1090C New Year Presents
  5. Scrapy中的Rules理解
  6. ES6(十八)Module
  7. c语言cmp函数含义,【C艹】关于sort用法之重构cmp(comp)函数的笔记
  8. html+css+js制作点名器
  9. 警告: PREMNMX is an obsolete function.解决办法
  10. java走台阶_走台阶算法 java实现