Android 通信简单应用
Table of Contents
1 Activity 之间通信
从一个 Activity
跳转到另一个 Activity
时,可以携带一些数据进去,这个就是 Activity
之间的通信
跳转到 Activity
之后可以响应通信,不过需要发起端调用 startActivityForResult
,接收端调用 setResult
这种通信方法我不能类比到组件之间的通信,组件之间通信都是单向数据流,这个是 双向数据流
1.1 原来的通信方法
1.1.1 通信发起端
跳转需要借助 Intent
对象,指定来源的上下文和目标的类,调用 startActivity
即可
Intent intent = new Intent(this, TargetClass.class); startActivity(intent)
如果需要携带数据,创建一个 Bundle
对象绑定到 Intent
即可
Intent intent = new Intent(this, TargetClass.class); Bundle bundle = new Bundle(); bundle.putString("message", "Hello World"); intent.putExtras(bundle); startActivity(intent);
其实也可以不用 Bundle
,直接给 Intent
来添加
1.1.2 通信接收端
跳转到接收端后,使用 getIntent
来获取对端的 Intent
对象,并查看绑定的数据
Intent intent = getIntent(); Bundle bundle = intent.getExtras();
1.1.3 双向数据流
通信发起端调用 startActivityForResult
并携带数据是一个方向,通信接收端调用 setResult
并携带数据与对端是另一个方向
在发起端
Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("message", "Hello"); intent.putExtras(bundle); startActivityForResult(intent, 2)
注意 startActivityForResult
第二个参数要大于0,才会接收对端的数据,并跳转到 onActivityResult
回调
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // 对端将数据写入 data ,可以从里面获取数据 }
在接收端回复
Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("result", "Fuck You"); intent.putExtras(bundle); setResult(RESULT_OK, intent); finish() // 结束声明周期,跳转到原来的 Activity
1.2 Result API 方法
Result API
是官方支持的方法,可以替代原来的通信方法,通信之间可以更加安全吧,应该
1.2.1 两边协定
在 Result API
下,两端的通信更像是函数,输入一个数据,函数会输出一个结果
两边需要定义一个协议,规定输入的数据类型和输出的数据类型
public class ResultContract extends ActivityResultContract<String, String>
为其定义 createIntent
方法,表示如何输入数据
public Intent createIntent(@NonNull Context context, String input) { Intent intent = new Intent(context, SecondActivity.class); intent.putExtra("name", input); return intent; }
为其定义 parseIntent
方法,表示如何解析接收到的输出数据
public String parseResult(int resultCode, @Nullable Intent intent) { String data = intent.getStringExtra("result"); if(resultCode == Activity.RESULT_OK && data != null) { return data; } else { return null; } }
1.2.2 输入端
使用 Result API
,页面跳转的方式也要改变了,需要一个 Launcher
来进行操作
这个 Launcher
的构造需要上面的两边协定和一个回调,这个回调用来处理 paserResult
后的数据
这里设置用 Toast
回显
ActivityResultLauncher activityLauncher = registerForActivityResult( new ResultContract(), result -> { Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show(); });
1.2.3 输出端
输出端的做法没有多大改变,一样的
button.setOnClickListener(view -> { Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("result", "Hello Mother Fucker"); intent.putExtras(bundle); setResult(RESULT_OK, intent); finish(); });
2 Fragment 之间通信
Framgent
之间的通信也想函数那样,输入一个值,输出一个值
不同的是,输入端需要在 FragmentManager
上设置一个 Listener
来接收输出值,并设置键 requestKey
提供位置
输出端需要通过 FragmentManager
来设置输出值到 requestKey
上
2.1 输入端
挑重要的来讲,输入端需要设置 requestKey
和处理输出值的回调
@Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); getParentFragmentManager().setFragmentResultListener( "requestKey", this, (requestKey, bundle) -> { String result = bundle.getString("bundleKey"); resultTextView.setText("Fuck You" + result); }); }
2.2 输出端
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment2, container, false); Button button = view.findViewById(R.id.button); button.setOnClickListener(_view -> { Bundle result = new Bundle(); result.putString("bundleKey", "result"); getParentFragmentManager().setFragmentResult("requestKey", result); }); return view; }
2.3 补充
以上都是同一级的 Fragment
之间通信,没涉及到父子之间通信,其实也是类似的
只需将 getParentFragmentManager
改为 getChildFragmentManager
即可
注意,他们都是用同一个 FragmentManager
来通信的