美文网首页
Activity Fragment 传值那些事

Activity Fragment 传值那些事

作者: 牧区叔叔 | 来源:发表于2020-10-28 07:29 被阅读0次

    最近涉及到传值问题,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、构造
      ===============================================================

    相关文章

      网友评论

          本文标题:Activity Fragment 传值那些事

          本文链接:https://www.haomeiwen.com/subject/ktyxvktx.html