Activity Fragment 传值那些事

最近涉及到传值问题,demo是fragment嵌套fragment

demo :

购物车demo

数据在购物车Fragment获取,我在传值给3个2代表的fragment;

这里涉及到fragment传值知识点,没怎么用过,所以总结下:
下图是日常传值结构(我自己想的,应该就这些吧,还有不足的留言补充下):

传值那些事

链接:https://blog.csdn.net/qq_33748378/article/details/53023036
链接:https://blog.csdn.net/lplj717/article/details/51209658

一、首先是activity之间的传值

1、通过startActivity来进行Activity的传值

在Android中,如果我们要通过一个Activity来启动另一个Activity,可以使用 startActivity(Intent intent)方法来传入一个Intent对象,这个Intent对象我们可以精确的指定我们需要跳转的Activity上,或者通过Intent对象来指定我们要完成的一个action操作,同时我们可以通过intent来携带一些值,进而来Activity见跳转的时候也可以把值传过去。
startActivity单纯的跳转页面,通过intent的putExtra()携带数据
Intent:方式一、setClass

 private void initView() {
        mTv = (TextView) findViewById(R.id.tv);
        final String str = "我是String类型";
        mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //方式1  2两写法 setClass
//                startActivity(new Intent(MainActivity.this,MainActivity2.class).putExtra("String",str));
                startActivity(new Intent().setClass(MainActivity.this,MainActivity2.class).putExtra("String",str));
                //方式2 利用setAction()
//                startActivity(new Intent().setAction("2222").putExtra("String",str));
            }
        });
    }

Intent:方式二 、通过setAction(),这个方式需要配置清单文件


setAction()--配置清单文件
 private void initView() {
        mTv = (TextView) findViewById(R.id.tv);
        final String str = "我是String类型";
        mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //方式1 常用到
//                startActivity(new Intent(MainActivity.this,MainActivity2.class).putExtra("String",str));
                //方式2 利用setAction()
                startActivity(new Intent().setAction("android.intent.action.2222").putExtra("String",str));
            }
        });
    }

2、通过startActivityForResult方法来得到Activity的回传值

在一些情况下,我们通过 A activity跳转到 B activity上,这时希望 A activtiy能从 B activity上得到一些返回值,这个时候我们就不能使用startActivity方法了,而是使用 startActivityForResult方法来完成我们的操作。这样的场景在实际开发中还是很常见的,比如说A activity中做了一个查询的功能,查询向后台请求数据假设需要传入一个时间字段,不传的话默认是当前时间,B activity中可以设置时间,那我们就可以在根据B activity 传回来的时间,在A activity 中就会有不同的查询结果。
在这里我之前想过A(startActivity)到B,B(startActivity)到A 不也是一个道理吗....?
---------记住【startActivityForResult()时候第二个页面点击跳转后一定不要忘记 finish()掉页面!不然挡住你页面,效果当然看不见啦】------------
MainActivity

package com.example.activity_fragment;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private TextView mTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

    }

    private void initView() {
        mTv = (TextView) findViewById(R.id.tv);
        final String str = "我是String类型";
        mTv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 * 第一个参数是Intent对象,第二个requestCode指定我们的一个启动标志值,因为我们可能有多个按钮,
                 * 如果都是跳转到同一个Activity对象上,我们需要对其进行标志,才知道是哪个Activity对象跳转过来的。
                 */
                startActivityForResult(new Intent(MainActivity.this,MainActivity2.class).putExtra("String",str),100);
            }
        });
    }

    /**
     * 所有的Activity对象的返回值都是由这个方法来接收
     * requestCode    If >= 0, this code will be returned in onActivityResult() when the activity exits.
     * @param requestCode 表示的是启动一个Activity时传过去的requestCode值
     * @param resultCode 表示的是启动后的Activity回传值时的resultCode值
     * @param data 表示的是启动后的Activity回传过来的Intent对象
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode==100&&resultCode==200){
            String main2 = data.getStringExtra("main2");
            mTv.setText(main2);
        }
    }
}

MainActivity2

package com.example.activity_fragment;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity2 extends AppCompatActivity {

    private TextView mTv2;
    private TextView mTv1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        initView();
        final Intent intent = getIntent();
        String tv = intent.getStringExtra("String");
        mTv2.setText(tv);
        mTv1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent.putExtra("main2","main2回传");
                setResult(200,intent);
                finish();
            }
        });
    }

    private void initView() {
        mTv2 = (TextView) findViewById(R.id.tv2);
        mTv1 = (TextView) findViewById(R.id.tv1);
    }
}

3、先把数据存在本地,然后在下一个Activity中从本地取。

这种方式涉及到数据存储,Android数据的四种持久化存储方式SharedPreferences、SQLite、Content Provider和File,该方式的缺点就是要占用本地的资源,优点是数据可以在多个Activity之间共享。关于这种Activity之间的传值以后会专门写一篇博客介绍,这里先谈下Activity之间传值的几种方式的主线。这里推荐一篇博客,可以大概了解下Android的几种数据存储方式 点击打开链接

4、多个Activity互相传值

例如A→B→C C在返回给A(例如,日常支付类就是)

5、使用EventBus框架

越来越多的项目开发中使用到EventBus这个框架,那什么是EventBus呢?用github开源文档上的介绍就是:一个Android平台的事件总线框架, 它简化了Activity、Fragment、Service等组件之间的交互,很大程度上降低了它们之间的耦合,使得我们的代码更加简洁,耦合性更低,提升我们的代码质量。

开发中我们都知道,很多时候要在Activty与Activty间,Activty与Fragment等之间传递数据进行交互,操作起来很不方便,我们以前可能会用到接口回调,或是用观察者模式来实现,或是发广播等等。这们操作不仅仅代码量大,而且代码耦合性高,性能不佳,也不便于维护。例如:两个Fragment之间的通信你会怎么实现? 按照Android官方给的建议的解决方法如下: Communicating with the Activity,思路就是Activity实现某个接口,然后在Fragment-A关联上Activity之后将Activity强转为接口类型,然后在某个时刻Fragment中回调这个接口,然后再从Activity中调用Fragment-B中方法。这个过程是不是有点复杂呢? 如果你也这么觉得,那也就是你继续看下去的理由了。

EventBus使用
1.依赖
2.在需要传值的类里边赋值
3.需要拿到数据的类中 注册 获取

总结 activity与activity(intent传值对象时候序列化实体类)
传值方式:

  • 1、startActivity
  • 2、startActivityForResult
  • 3、EventBus
    ===============================================================

二、Activity与fragment之间的传值

链接:https://blog.csdn.net/weixin_40438421/article/details/104137883

1、利用setArguments()的传值(Arguments的参数需要bundle,所以把需要传的值利用bundle存进去)

效果:


Arguments()实现传值

activity代码

   private void initView() {
        mFl = (FrameLayout) findViewById(R.id.fl);
        mRg = (RadioGroup) findViewById(R.id.rg);
        mBt1 = (RadioButton) findViewById(R.id.bt1);
        mBt2 = (RadioButton) findViewById(R.id.bt2);
        final Bundle bundle = new Bundle();
        mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId){
                    case R.id.bt1:
                        bundle.putString("main1","你好Fragment,我是从activity过来的【1】。");
                        AFragment aFragment = new AFragment();
                        aFragment.setArguments(bundle);
                        getSupportFragmentManager().beginTransaction().replace(R.id.fl,aFragment).commit();
                        break;
                    case R.id.bt2:
                        bundle.putString("main2","你好Fragment,我是从activity过来的【2】。");
                        BFragment bFragment = new BFragment();
                        bFragment.setArguments(bundle);
                        getSupportFragmentManager().beginTransaction().replace(R.id.fl,bFragment).commit();
                        break;
                    default:
                        throw new IllegalStateException("Unexpected value: " + checkedId);
                }
            }
        });
    }

A、Bfragment代码

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View inflate = inflater.inflate(R.layout.fragment_b, container, false);
        Log.i("sm", "B--onCreateView: ");
        String string = getFragmentManager().findFragmentById(R.id.fl).getArguments().getString("main2");
        Log.i("bn", string);
        return inflate;
    }

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View inflate = inflater.inflate(R.layout.fragment_a, container, false);
        Log.i("sm", "A--onCreateView: ");
        String string = getFragmentManager().findFragmentById(R.id.fl).getArguments().getString("main1");
        Log.i("bn", string);
        return inflate;
    }

2、利用EventBus传值

什么鬼?普通事件传不了?


image.png

百度了半天才知道我把发送事件写在跳转里边了!
就是点击跳转到SecondActivity或者加载fragment的时候在EventBus注册之前,消息已经发送了,因此才会出现上面的错误。

粘性事件使用场景
我们要把一个Event发送到一个还没有初始化的Activity/Fragment,即尚未订阅事件。那么如果只是简单的post一个事件,那么是无法收到的,这时候,你需要用到粘性事件,它可以帮你解决这类问题.
那么点击事件里怎么解决问题呢?
需要用到粘性事件!EventBus分普通和粘性!
粘性发送消息的意思是如果没有接收到消息会一直发送最新消息!直到接收为止。

效果:


粘性事件

粘性事件代码
activity

 private void initView() {
        mFl = (FrameLayout) findViewById(R.id.fl);
        mRg = (RadioGroup) findViewById(R.id.rg);
        mBt1 = (RadioButton) findViewById(R.id.bt1);
        mBt2 = (RadioButton) findViewById(R.id.bt2);
        final Bundle bundle = new Bundle();
        mRg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId){
                    case R.id.bt1:
//                        bundle.putString("main1","你好Fragment,我是从activity过来的【1】。");
                        AFragment aFragment = new AFragment();
//                        aFragment.setArguments(bundle);
                        getSupportFragmentManager().beginTransaction().replace(R.id.fl,aFragment).commit();
//                        EventBus.getDefault().post("发送成功");//普通
                        EventBus.getDefault().postSticky("发送成功");//粘性
//                        startActivity(new Intent(MainActivity.this,MainActivity2.class));
//                        break;
//                    case R.id.bt2:
////                        bundle.putString("main2","你好Fragment,我是从activity过来的【2】。");
//                        BFragment bFragment = new BFragment();
////                        bFragment.setArguments(bundle);
//                        getSupportFragmentManager().beginTransaction().replace(R.id.fl,bFragment).commit();
//                        break;
                    default:
                        throw new IllegalStateException("Unexpected value: " + checkedId);
                }
            }
        });
    }

fragment

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View inflate = inflater.inflate(R.layout.fragment_a, container, false);
//        Log.i("sm", "A--onCreateView: ");
//        String string = getFragmentManager().findFragmentById(R.id.fl).getArguments().getString("main1");
//        Log.i("bn", string);
        EventBus.getDefault().register(this);//注册订阅者,在onCreateView中注册

        return inflate;
    }

 @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("sm", "A--onDestroy: ");
        EventBus.getDefault().unregister(this);//反注册订阅者,在onDestory中反注册
    }


 //接收事件
    @Subscribe(sticky = true)  //粘性事件用这个
//    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(String string){  //函数名字自定义!
        Log.i("bn", string);
    }

粘性事件总结:

依赖:implementation 'org.greenrobot:eventbus:3.1.1'
发送:EventBus.getDefault().postSticky("我是粘性事件");
注册:EventBus.getDefault().register(this);//注册订阅者,在onCreateView中注册
销毁:EventBus.getDefault().unregister(this);//反注册订阅者,在onDestory中反注册
接收: @Subscribe(threadMode = ThreadMode.MAIN,sticky = true)或者 @Subscribe(sticky = true)都可以
public void onMessageEvent(String string){
Log.i("bn", string);
}
手动获取或者移除:student stickyEvent = EventBus.getDefault().getStickyEvent(student.class);
if (stickyEvent!=null){
EventBus.getDefault().removeStickyEvent(stickyEvent);
}

3、接口回调

步骤
1、创建接口(内外部)
2、activity实现接口,重写方法
3、fragment内定义接口,并赋值(在Attach()方法里)
4、fragment需要的位置调用接口

效果:


接口实现传递

外接口代码


image.png

内接口代码


image.png

定义接口并赋值


image.png

activity实现的方法


image.png

4、通过构造

image.png

总结 activity与fragment交互

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