返回

从Activity中获取Service返回值的进阶指南:绕过startActivityForResult()

Android

从 Activity 返回值到 Service 的进阶指南

问题陈述

如何从在 Service 中启动的 Activity 中获取返回值?startActivityForResult() 不适用于 Service,而且该函数已弃用。

限制

  • Service 是从外部调用的,因此必须使用它。
  • 数据必须在 Service 执行流程中接收。因此,不适合从 Service 启动 Activity,然后从 Activity 中启动 Service。在 Activity 中,你需要填写一些值,然后使用接收的数据将控制权返回到 Service,位置与 Service 入口点相同。
  • 目标 Android 版本为 6.0(API 23)。这可能也会限制一些可能性。

解决方法

现在,我们可以通过一个带有内部映射的同步单例实现这个功能。该单例将充当 Service 和 Activity 之间的通信桥梁。

步骤

  1. 在 Service 中创建同步单例

    • 创建一个带有内部映射的同步单例,用于存储 Activity 返回的值。
  2. 在 Service 中创建 Map

    • 在单例中创建一个 Map,用于存储 Activity 返回的值。
  3. 在 Activity 中启动 Service

    • 使用 Intent 启动 Service 并发送请求。
  4. 在 Activity 的 onActivityResult() 方法中,将结果值添加到 Service 中的 Map 中

    • 在 Activity 的 onActivityResult() 方法中,将结果值添加到 Service 中的 Map 中。
  5. 在 Service 中,使用同步锁从 Map 中获取结果值

    • 在 Service 中,使用同步锁从 Map 中获取结果值。

代码示例

Service.java

public class MyService extends Service {

    private static final Object lock = new Object();
    private static Map<String, Object> resultValues = new HashMap<>();

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

    public static Object getResultValue(String key) {
        synchronized (lock) {
            return resultValues.get(key);
        }
    }

    public class MyBinder extends Binder {
        public MyService getService() {
            return MyService.this;
        }
    }
}

Activity.java

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...

        // 启动 Service 并发送请求
        Intent intent = new Intent(this, MyService.class);
        startActivityForResult(intent, 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == 1 && resultCode == RESULT_OK) {
            // 将结果值添加到 Service 中的 Map 中
            synchronized (MyService.lock) {
                MyService.resultValues.put("result", data.getStringExtra("result"));
            }
        }
    }
}

使用说明

在 Service 中,可以使用以下代码从 Map 中获取结果值:

Object resultValue = MyService.getResultValue("result");

注意事项

  • 确保在 Activity 和 Service 中使用相同的键来存储和检索结果值。
  • 在 Activity 中,记得在 onActivityResult() 方法中设置 RESULT_OK 结果代码,以便 Service 知道请求已成功完成。

结论

通过使用同步单例和 Map,我们可以从在 Service 中启动的 Activity 中获取返回值。这为在 Activity 和 Service 之间进行通信提供了灵活且可靠的方法。

常见问题解答

  1. 我能否在 Android 10 及更高版本上使用此方法?

    • 是的,此方法可以在 Android 10 及更高版本上使用。
  2. 可以使用其他方法吗?

    • 是的,还有其他方法可以实现此功能,例如使用消息传递或广播。但是,此方法使用起来相对简单且高效。
  3. 如何在 Service 中获得 Activity 的上下文?

    • 无法在 Service 中直接获得 Activity 的上下文。相反,你应该使用 Intent 在 Activity 和 Service 之间传递数据。
  4. 我收到“无法转换目标类型”错误。我该怎么做?

    • 确保在将值放入 Map 之前将其转换为正确的类型。例如,如果值是一个字符串,则需要使用 String 类型的键。
  5. 此方法适用于跨多个 Activity 的情况吗?

    • 是的,此方法可以适用于跨多个 Activity 的情况。只需确保在每个 Activity 中使用相同的键来存储和检索结果值即可。