Activity&Fragment通信全解

用户场景

设想这样一种用户场景:
在个人信息展示界面, 用户点击编辑按钮, 跳转到编辑界面, 完成编辑后, 回退到个人信息展示界面, 此时界面上应该展示最新的数据.
这里涉及到编辑后的数据如何及时更新到个人信息界面, 也即Activity&Fragment之间如何通信的问题.

分析

由于Fragment需要依托于Activity存在, 故有如下几种通信场景:

Activity&Fragment通信的几种场景

乍看上去可能不太好理解, 来依次分析下这几种场景.

1.Activity与Activity通信

此场景最为常见, 用户从Activity A跳转到Activity B, 通过Activity A的startActivity(Intent intent)方法, 可以在Intent中附加信息, 在打开Activity B的同时将这些信息传递给Activity B.
那么Activity B如何传递信息回Activity A呢? 使用setResult()方法即可. 很基础的用法, 下面列出一些需要注意的点:

a

调用setResult()后Activity A并不会立刻调用onActivityResult()回调, 而是当Activity B finish后才会调用.

2.Activity与其中的Fragment通信

Activity -> Fragment

Activity A中包含了Fragment B. 如何传递数据给Fragment B呢?
建议使用Fragment.setArguments().
我们也可以通过Fragment的构造方法传递参数, 但这是不推荐的. 当配置发生变化(语言发生变化, 屏幕发生旋转等), Activity会发生重建, 依附于其上的Fragment也会重建, 系统会调用Fragment的默认无参构造方法(如果我们实现了有参的构造方法, 会导致系统在重建Fragment时找不到无参构造方法, 会崩溃.) 而我们通过setArgument设置的参数在重建时会自动恢复, 这样就不会丢失数据了. 我们看一个使用setArgument的实例:

SomeFragment fragment = new SomeFragment();
Bundle args = new Bundle();
args.putString(SOME_EXTRA, "some_args");
fragment.setArguments(args);
getSupportFragmentManager()
                        .beginTransaction()
                        .replace(R.id.fragment_container, fragment)
                        .commit();

通过这种方式创建的Fragment在屏幕旋转等情况下还能保持通过setArgument设置的参数.

上面说的是创建Fragment时Activity如何传递参数给Fragment, 当Fragment创建后, Activity如何向Fragment发送消息呢? 我们要用到下面两个方法:

getSupportFragmentManager().findFragmentById(R.id.fragment_container);
getSupportFragmentManager().findFragmentByTag("some_tag");

这两个方法可以获取到想要的Fragment实例, 进而可以调用其方法向其传递消息.

Fragment -> Activity

那么Fragment如何与其宿主Activity通信呢? 诚然, 我们可以通过在Fragment中调用getActivity()获取其宿主Activity, 并将其强制转换为宿主Activity的类型, 并调用其中的方法, 达到Fragment向其Activity传递参数的目的, 如下:

SomeActivity activity = (SomeActivity) getActivity();
activity.someMethod();

Fragment被设计为可复用的模块化Activity组件, 为了保证其可复用性, 我们应该避免在Fragment中直接调用其他Fragment或Activity的方法, 因为这样会导致Fragment与特定的Activity/Fragment耦合, 无法实现其可复用性.
我们应该在Fragment中定义一个接口, 需要与之通信的Activity实现其接口:

class SomeFragment extends Fragment {
    ...
    interface ICommunication {
        void communicate(...);
    }
    
    void sendMessageToActivity() {
        ((ICommunication)getActivity()).communicate(...);
    }
}

class ParentActivity extend FragmentActivity implements ICommunication {
    @Override
    void communicate(...) {
        //TODO do some thing
    }
}

这样做, 宿主Activity需要实现Fragment定义好的通信接口, 保证了Fragment的可复用性.
PS: 是否有更好的方式?

3.同Activity中的两个平级Fragment通信

我们为了保证Fragment的可复用性, 绝对不能在一个Fragment中直接调用另一个Fragment的方法. 那两个平级的Fragment如何通信呢, 很简单, 通过父Activity中中转一下就可以了, 用上面列出的两种方法.

平级Fragment通信

4.子Activity中的Fragment和父Activity如何通信?

2 --> 1

Fragment先与子Activity通信, 子Activity再通过setResult将消息传递给父Activity, done.


2 --> 1

5.子Fragment与父Fragment间通信

我们先看简单的情况, 父Fragment如何与子Fragment通信?

创建时

老生常谈了, 用setArguments()向子Fragment传递参数, 这样在配置变化重建Fragment时, 参数也能恢复.

运行时

因为子Fragment是直接在父Fragment里new出来的, 父Fragment是保存有子Fragment的引用的, 既然有引用, 就可以直接调用子Fragment的成员方法了. 因为父Fragment就是要new特定类型的子Fragment, 不存在可复用性的影响, 类似宿主Activity持有Fragment引用.

再来看复杂一点的情况, 子Fragment如何与父Fragment通信? 不要跟我说用:

getActivity().getSupportFragmentManager().findFragmentById(R.id.fragment_container);

子Fragment设计出来是为了复用的, 这样做, 子Fragment就知道一定有一个特定类型的父Fragment, 还要去调用父Fragment特定的方法, 这样谈何复用?
正确的姿势在这里:
父Fragment在创建子Fragment时, 这样操作:

public static final int REQUEST_CODE = 1024;
...
ChildFragment childFragment = ChildFragment.newInstance(someArguments);
childFragment.setTargetFragment(this, REQUEST_CODE);  //this是父Fragment的引用, 向上转型为Fragment
//show child fragment...

这里子Fragment将父Fragment设置为其TargetFragment, 并设置了requestCode.
当子Fragment需要传递数据回父Fragment时:

public class ChildFragment extends Fragment {
    ...
    //需要传递数据时调用
    private void setResult(SomeType someData) {
        Intent intent = new Intent();
        intent.putExtra(SOME_EXTRA, someData);
        getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, intent);
    }
}

是不是很惊讶, 居然调用了Fragment.onActivityResult()方法.

Fragment.onActivityResult()

该方法是Fragment实现的一个通用空方法, 我们继承的Fragment都有这个方法, 由于是通用的, 也就不存在破坏复用性的问题.
getTargetRequestCode()可以拿到子Fragment创建时传入的requestCode, Intent用来装载数据. 我们在父Fragment中复写onActivityResult()方法, 这样就可以传回数据到父Fragment啦~

public class ParentFragment extends Fragment {
    ...
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        //我们根据requestCode判断是哪个子Fragment传回的数据
        //从data中拿到传回的数据
    }
}

6.父Activity的Fragment与子Activity的Fragment之间通信

这种情况就很简单啦, 套用上面的5点, 相信你可以解决~

以上

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,057评论 25 707
  • Fragment要点 1、Fragment作为Activity界面的一部分组成出现 2、可以在一个Activity...
    玉圣阅读 1,215评论 0 16
  • 《Android Fragment完全解析,关于碎片你所需知道的一切》 我们都知道,Android上的界面展示都是...
    cxm11阅读 2,165评论 2 19
  • 我想说 今天的太阳很漂亮 今天的天空很澄净 自由的空气清晰透明 芬芳的花朵温馨恬静 我想说 今天的自己很开心 自由...
    叶浟阅读 300评论 0 5
  • 这篇听了好几遍,仍然有不少地方没听懂,只好读原文了。大致讲的就是南美洲的食人鱼,piranha(发音:peh'ra...
    木木卡卡西阅读 663评论 0 0