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、构造
===============================================================