Activity 组件通信与 Scheme 跳转

1. Activity 与 Activity 通信

最常见方式是:

Intent + Bundle

示例:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);

Bundle bundle = new Bundle();
bundle.putString("data_string", "数据");
bundle.putInt("data_int", 10);
bundle.putChar("data_char", 'a');

intent.putExtras(bundle);
startActivity(intent);

SecondActivity 中接收:

Bundle bundle = getIntent().getExtras();

if (bundle != null) {
    String dataString = bundle.getString("data_string");
    int dataInt = bundle.getInt("data_int");
    char dataChar = bundle.getChar("data_char");
}

适合传递:

字符串
数字
布尔值
Parcelable 对象
Serializable 对象

不适合传递大量数据。


2. 不推荐滥用静态变量通信

可以用静态变量传少量临时数据:

public class DataHolder {
    public static String username;
}

写入:

DataHolder.username = "张三";

读取:

String name = DataHolder.username;

但是不推荐大量使用,因为:

进程被杀后数据会丢
生命周期不安全
容易造成内存泄漏
数据来源不清晰
不适合跨进程

更推荐:

Intent
ViewModel
Repository
数据库
DataStore
SharedPreferences

3. Activity 与 Service 通信:绑定服务

如果 Activity 需要和 Service 长时间交互,可以使用绑定服务。

Service 中提供 Binder:

public class MyService extends Service {

    private String data;

    public class MyBinder extends Binder {
        public void sendData(String value) {
            data = value;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
}

Activity 中绑定 Service:

private MyService.MyBinder binder;

private final ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        binder = (MyService.MyBinder) service;
        binder.sendData("来自 Activity 的数据");
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        binder = null;
    }
};

绑定:

Intent intent = new Intent(this, MyService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);

解绑:

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindService(connection);
}

实际项目中要注意避免重复解绑,可以维护一个 bound 标记。


4. Activity 与 Service 通信:Intent 传值

如果只是启动 Service 时传少量参数,可以直接用 Intent。

原 PDF 示例中这里有一个明显错误:

startActivity(intent);

启动 Service 应该使用:

startService(intent);

正确示例:

Intent intent = new Intent(this, MyService.class);
intent.putExtra("data_string", "string数据");
startService(intent);

Service 中接收:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null) {
        String data = intent.getStringExtra("data_string");
    }

    return START_NOT_STICKY;
}

适合:

启动服务时传递参数
一次性命令
少量数据传递

5. 版本差异:Service 后台限制

Android 8.0 / API 26 之后,后台 Service 受到更多限制。

如果需要执行用户可感知的长期任务,应该考虑:

Foreground Service
WorkManager
JobScheduler

例如:

音乐播放
导航
录音
文件上传下载
定时同步

不要把长期后台任务简单理解为:

startService() 后就一直稳定运行

这在现代 Android 上不可靠。


6. Service 回调 Activity:Callback + Handler

如果 Service 中有耗时任务,任务完成后需要通知 Activity,可以使用:

Callback + Handler

基本思路:

Activity 绑定 Service
Activity 把 Callback 传给 Service
Service 执行任务
Service 通过 Callback 通知 Activity
Activity 用 Handler 切回主线程更新 UI

因为 Android 只能在主线程更新 UI,如果 Service 回调发生在子线程中,需要切回主线程:

handler.post(() -> {
    // 更新 UI
});

或者使用:

LiveData
StateFlow
Broadcast
Messenger
AIDL

根据场景选择。


7. Activity 与 Fragment 通信:Bundle

Activity 创建 Fragment 时,可以通过 setArguments() 传递参数。

Activity 中:

Bundle bundle = new Bundle();
bundle.putString("data_string", "数据");
bundle.putInt("data_int", 10);

Fragment fragment = new MyFragment();
fragment.setArguments(bundle);

Fragment 中:

Bundle bundle = getArguments();

if (bundle != null) {
    String data = bundle.getString("data_string");
    int number = bundle.getInt("data_int");
}

这种方式适合 Fragment 初始化参数。


8. Activity 直接调用 Fragment 方法

Activity 也可以拿到 Fragment 引用后,直接调用它的方法:

MyFragment fragment = new MyFragment();
fragment.updateData("传递的数据");

Fragment 中:

public void updateData(String data) {
    // 更新 Fragment 数据
}

但要注意生命周期。

如果 Fragment 还没 attach,或者 View 还没创建,直接更新 UI 可能会出问题。

更推荐的现代方式:

同一 Activity 内共享 ViewModel
Fragment Result API
接口回调
Navigation Component 参数传递

9. Scheme 跳转协议

Scheme 是一种页面跳转协议。

例如:

myapp://product/detail?id=100

它可以让外部页面或系统通知跳转到 App 内指定页面。

常见场景:

H5 页面打开 App 指定页面
通知栏点击跳转详情页
短信链接唤起 App
运营活动页跳转 App 内页
服务器下发跳转路径

10. Scheme 的基本配置

Manifest 中配置:

<activity android:name=".ProductDetailActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data
            android:scheme="myapp"
            android:host="product"
            android:path="/detail" />
    </intent-filter>
</activity>

链接:

myapp://product/detail?id=100

Activity 中获取参数:

Uri uri = getIntent().getData();

if (uri != null) {
    String id = uri.getQueryParameter("id");
}

方式 特点
自定义 Scheme 简单,容易接入,但可能被其他 App 抢占
Android App Links 基于 HTTPS 和域名验证,更适合生产环境外部链接跳转

简单理解:

内部约定跳转:Scheme 可以用
正式 Web 链接唤起 App:优先考虑 App Links

12. 总结

通信对象 推荐方式
Activity → Activity Intent / Bundle
Activity → Service bindService / startService + Intent
Service → Activity Callback + Handler / LiveData / Flow / Broadcast
Activity → Fragment setArguments
Fragment → Activity 共享 ViewModel / 接口回调 / Fragment Result API
外部 → App 页面 Scheme / App Links

记忆口诀:

页面传页面,用 Intent。
页面传 Fragment,用 Arguments。
页面连 Service,用 Binder。
外部跳 App,用 Scheme 或 App Links。

参考来源