燕过留声:由 Activity 和 Fragment 的通信方法想到的【WIP】
今天查看 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】相关推荐
- 安卓APP_ Fragment(2)—— Activity与Fragment的通信
摘自:安卓APP_ Fragment(2)-- Activity与Fragment的通信 作者:丶PURSUING 发布时间: 2021-04-16 17:23:44 网址:https://blog. ...
- android 小卷毛播放器,Android 音乐播放器的开发教程(四)Activity和Fragment的通信以及Fragment的切换 ----- 小达...
Activity和Fragment的通信以及Fragment的切换 在上一篇的博客中讲到了,播放器的主界面布局,是由一个activity和一个fragment构成的,activity启动的时候,在其o ...
- Android:手把手教你 实现Activity 与 Fragment 相互通信(含Demo)
https://blog.csdn.net/carson_ho/article/details/75453770 转载于:https://www.cnblogs.com/geili/p/1069967 ...
- android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案
前言 最近一直在想着能否有一种更好的方案来解决:Android中Activity与Fragment之间通信的问题,什么叫更好呢,就是能让Fragment的复用性高,性能还有好(不用反射),代码还要好维 ...
- Lifecycle Activity和Fragment生命周期感知组件 LifecycleObserver MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Activity与Fragment的生命周期详解
在安卓中Activity与Fragment是非常相似的两个类,它们各自都拥有自己的生命周期,且都可以用来显示布局文件中的视图.其中Activity是通过setContenView()显示视图,而Fra ...
- Android Activity和Fragment的转场动画
Activity转场动画 Activity的转场动画是通过overridePendingTransition(int enterAnim, int exitAnim)实现的. 这个方法是API Lev ...
- activity中fragment 返回键不退出_优雅地处理加载中(loading),重试(retry)和无数据(empty)等...
LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面,可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,占位图,登录失效等常 ...
- 多个Activity与Fragment之间的数据传递
多个Activity与Fragment之间数据传递 问题描述 解决思路 具体解决 bug de到亲妈落泪. 问题描述 首先展示个人问题的整体框架: ActivityA:主页面,有一个PageView控 ...
- Android 如何快速定位当前页面是哪个Activity or Fragment
在日常需求开发中,经常碰到不太熟悉的模块,如何快速定位相应页面对应的Activity/Fragment ? (1)查看当前Activity :adb shell "dumpsys wind ...
最新文章
- flume数据丢失与重复_Flume架构及常见面试
- DNS and Bind (一)
- Nginx使用openssl生成证书文件
- 软件工程---第四章---形式化分析
- git add remote_使用git管理嵌入式软件版本
- MATLAB(六)数据处理
- 怎么修剪_幸福树怎么修剪——武汉花卉租摆
- js 防止重复提交方案
- 随想录(项目管理中的感受)
- python3 一年中的天数 时间转化为北京时_三年级数学《年月日》时间知识详解,帮助孩子重点知识不丢分...
- python可以做exe文件吗_手动制作python的exe可执行程序
- Windows驱动开发TraceView之日志打印
- 三角函数之间的转换公式
- UI面试常见问题总结
- 局域网即时通讯软件_企业即时通讯软件需要符合哪些要求?
- 磷脂PEG磷脂,DSPE-PEG-DSPE
- 苏轼:醉笑陪君三万场 不诉离殇
- 社工计算机技能考试考什么,社会工作者考试内容是什么?(附社工考试科目、考试教材和考试题型)...
- GitHub 上有什么好玩又有挑战的前端项目?
- 用python画国旗的程序_利用python画国旗(示例)
热门文章
- 模拟器桥接模式下 WLAN 无法连接及安卓 7.0+ 无法抓包 HTTPS 的解决
- 字体反爬-起点网月票榜案例
- 为什么要用深浅拷贝、什么是深浅拷贝、以及如何实现
- Codeforces 1090C New Year Presents
- Scrapy中的Rules理解
- ES6(十八)Module
- c语言cmp函数含义,【C艹】关于sort用法之重构cmp(comp)函数的笔记
- html+css+js制作点名器
- 警告: PREMNMX is an obsolete function.解决办法
- java走台阶_走台阶算法 java实现