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
2022-03-08_20-46-33_screenshot.png

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 之间通信,没涉及到父子之间通信,其实也是类似的
2022-03-08_20-50-31_screenshot.png
只需将 getParentFragmentManager 改为 getChildFragmentManager 即可
注意,他们都是用同一个 FragmentManager 来通信的

Author: Steiner

Created: 2022-03-11 五 22:37

Validate