当前位置: 首页 > news >正文

Robolectric拿到当前的Activity

Robolectric 测试中,获取当前正在显示 / 处于前台的 Activity 是一个常见的需求,尤其是在以下场景中:

  • 你启动了一个新的 Activity(比如通过 Intent 跳转、广告落地页、DeepLink 等),
  • 你想验证这个 Activity 是否正确启动,
  • 或者你想对这个 当前 Activity 做进一步的 UI 操作、断言等。

❓ 问题:如何在 Robolectric 中获取“当前” Activity?

在 Android 真实系统中,我们可能通过一些方式(比如 ActivityLifecycleCallbacks 或 Application 的 activity 栈)获取当前 Activity,但在 Robolectric 测试环境 中,没有真正的系统 Activity 栈管理。

不过,Robolectric 提供了一个非常简单且可靠的方法:

通过 **ShadowApplication**获取最近启动的 Activity(即当前正在运行的 Activity)


✅ 正确方法:使用 ShadowApplication获取最新的 Activity

Robolectric 提供了 ShadowApplication,它可以追踪通过 startActivity(Intent)启动的 Activity,因此:

✅ 你可以这样获取 最近启动的(也就是当前显示的)Activity

// 1. 获取当前 Application 的 Shadow
ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.getApplication());// 2. 获取最近启动的 Intent(即通过 startActivity 启动的)
Intent startedIntent = shadowApplication.getNextStartedActivity();// 3. 如果你只是想获取这个 Intent 对应的 Activity 类,可以这样:
if (startedIntent != null) {Class<?> startedActivityClass = startedIntent.getComponent().getClassName();System.out.println("启动的 Activity 类名: " + startedActivityClass);
}// 4. 如果你想真正获取这个 "当前" Activity 的实例,你有两个方式:// 方式一:如果你已经通过 Robolectric.buildActivity(...) 启动它,那直接使用返回的实例即可
// 比如:
// MyActivity activity = Robolectric.buildActivity(MyActivity.class).create().get();
// 这个 activity 就是你当前的测试对象// 方式二:如果你是通过 startActivity(Intent) 启动的(比如广告跳转、页面跳转等),
// 那么 Robolectric **并不会自动创建 Activity 实例**,它只是记录了 Intent。
// 所以,你如果想拿到这个 "被启动的 Activity 实例",需要手动用 Robolectric 构建它,如下:
if (startedIntent != null) {String activityClassName = startedIntent.getComponent().getClassName();try {Class<?> activityClass = Class.forName(activityClassName);if (Activity.class.isAssignableFrom(activityClass)) {@SuppressWarnings("unchecked")Class<? extends Activity> activityClazz = (Class<? extends Activity>) activityClass;// 模拟构建并“启动”这个 Activity(你可以传入 Intent)Activity launchedActivity = Robolectric.buildActivity(activityClazz, startedIntent).create().start().resume().get();// ✅ 这个 launchedActivity 就是你想拿的“当前” ActivitySystem.out.println("模拟启动的当前 Activity: " + launchedActivity.getClass().getSimpleName());// 你可以对这个 Activity 做断言或 UI 操作// 例如:TextView tv = launchedActivity.findViewById(R.id.xxx);}} catch (ClassNotFoundException e) {fail("无法加载被启动的 Activity 类: " + activityClassName);}
}

✅ 更常见的情况:你手动启动了 Activity,直接用它的返回值

绝大多数 Robolectric 单元测试中,你其实 是直接通过 **Robolectric.buildActivity(...)**来启动 Activity 的,比如:

@Test
public void testMyActivity() {// 🟢 这是你启动 Activity 的地方MyActivity activity = Robolectric.buildActivity(MyActivity.class).create().start().resume().get();// ✅ 那么这个 `activity` 就是当前你启动的 Activity,你可以直接使用它!assertNotNull(activity);TextView textView = activity.findViewById(R.id.text_view);assertEquals("Hello Robolectric", textView.getText().toString());
}

🔍 在这种情况下,“当前 Activity” 就是你通过 **.get()**拿到的这个 activity 对象。

✅ 所以,如果你是自己通过 Robolectric 启动的 Activity,那么你根本不需要去“获取”当前 Activity,因为你已经有了它的引用!


✅ 特殊情况:通过 startActivity(Intent) 启动的 Activity(比如模拟跳转)

如果你在测试中 调用了某个对象的 startActivity(Intent) (比如你的广告模块、点击事件、Router 跳转等),例如:

// 模拟某个广告点击后启动一个落地页 Activity
Intent intent = new Intent(ApplicationProvider.getApplicationContext(), AdDetailActivity.class);
someObject.startActivity(intent);  // 例如:context.startActivity(intent);

那么:

  • Robolectric 不会自动实例化 AdDetailActivity
  • 但它会 记录你调用了 startActivity(intent)
  • 你可以用 ShadowApplication.getNextStartedActivity()拿到这个 Intent,
  • 然后 手动用 Robolectric 构建并启动这个 Activity,从而拿到它的实例(即你想要的“当前” Activity)。

✅ 总结:如何在 Robolectric 中获取“当前 Activity”

场景说明如何获取“当前 Activity”
你手动用 Robolectric 启动了 Activity(推荐方式)
比如:Robolectric.buildActivity(MyActivity.class)...get()
你完全掌握 Activity 的创建过程直接通过 **.get()**拿到的对象就是当前 Activity
🧩 你通过某个代码逻辑(如点击、路由、广告 SDK)调用了 startActivity(Intent)Robolectric 记录了 Intent,但不会自动创建 Activity 实例1. 用ShadowApplication.getNextStartedActivity()拿到 Intent
2. 解析出目标 Activity 类名
3. 用Class.forName()+Robolectric.buildActivity(...)手动构建并启动它
4. 最终.get()就是你想拿的“当前” Activity
你试图获取系统当前栈顶的 Activity(像在真机那样)Robolectric 没有真实的 Activity 栈管理,不能像ActivityManager那样获取Robolectric 不提供直接获取“当前正在显示的 Activity”的 API,你必须自己管理或跟踪

✅ 推荐的最佳实践

✅ 如果是你自己启动的 Activity(推荐写法):

@Test
public void testActivityIsLaunchedAndVisible() {// 1. 你自己启动 ActivityMyActivity activity = Robolectric.buildActivity(MyActivity.class).create().start().resume().get();// 2. 这个 activity 就是“当前”的 Activity,直接使用即可assertNotNull(activity);// 3. 做 UI 测试、断言等TextView tv = activity.findViewById(R.id.text_view);assertEquals("Hello", tv.getText().toString());
}

👉 这个 **activity**就是你当前测试的、处于 resumed 状态的 Activity,也就是你想要的“当前 Activity”。


✅ 如果是其他代码调用了 startActivity(Intent)(你要捕获它):

@Test
public void testAdClickLaunchesAdActivity() {// 1. 模拟点击广告,内部会调用 startActivity(intent)expressAd.show(hostActivity, null);// 2. 捕获启动的 IntentIntent startedIntent = Shadows.shadowOf(RuntimeEnvironment.getApplication()).getNextStartedActivity();assertNotNull(startedIntent);// 3. 拿到目标 Activity 类名String className = startedIntent.getComponent().getClassName();Class<?> activityClass;try {activityClass = Class.forName(className);} catch (ClassNotFoundException e) {fail("找不到启动的 Activity 类: " + className);return;}// 4. 确保是 Activityif (!Activity.class.isAssignableFrom(activityClass)) {fail("启动的不是 Activity: " + className);return;}// 5. 手动构建并“启动”这个 Activity@SuppressWarnings("unchecked")Class<? extends Activity> activityClazz = (Class<? extends Activity>) activityClass;Activity launchedActivity = Robolectric.buildActivity(activityClazz, startedIntent).create().start().resume().get();// 6. 这个 launchedActivity 就是你想拿的“当前” ActivityassertNotNull(launchedActivity);
}

❗ Robolectric 没有直接获取“当前 Activity”的 API

⚠️ 注意:Robolectric 不提供类似于 **getCurrentActivity()** **getTopActivity()**这样的方法!

原因是 Robolectric 没有维护一个真实的系统级 Activity 栈,它只是模拟了单个 Activity 的生命周期和行为。

所以如果你想获取“当前” Activity,你必须 自己启动它并持有引用,或者 通过 Intent 捕获并手动构建它


✅ 总结一句话

你想获取的“当前 Activity”是怎么来的?你应该怎么做?
是你自己通过Robolectric.buildActivity(...).get()启动的直接使用.get()返回的 Activity 对象,它就是“当前”的
是通过某个代码(如广告、点击事件)调用了startActivity(intent)ShadowApplication.getNextStartedActivity()捕获 Intent,再通过Class.forName + Robolectric.buildActivity(...)手动构建并启动,.get()就是你要的 Activity
你希望有现成的 API 如getCurrentActivity()Robolectric 没有提供,你必须自己管理 Activity 的启动和引用
http://www.dtcms.com/a/359184.html

相关文章:

  • 轻量化模型-知识蒸馏1
  • Wheat Gene ID Convert Tool 小麦中国春不同参考基因组GeneID转换在线工具
  • 2025年外贸服装跟单管理软件TOP3推荐榜单
  • 手动安装的node到nvm吧版本管理的过程。
  • 基于Docker部署的Teable应用
  • [特殊字符]️ STL 容器快速参考手册
  • 海盗王64位dx9客户端修改篇之三
  • 【有序集合 有序映射 懒删除堆】 3510. 移除最小数对使数组有序 II|2608
  • 9. 函数和匿名函数(一)
  • enumerate 和for in搭配使用
  • 接雨水,leetCode热题100,C++实现
  • 【随笔】【Debian】【ArchLinux】基于Debian和ArchLinux的ISO镜像和虚拟机VM的系统镜像获取安装
  • C++的迭代器和指针的区别
  • 「日拱一码」066 深度学习——Transformer
  • Flutter MVVM+provider的基本示例
  • Qt中的锁和条件变量和信号量
  • Science:机器学习模型进行遗传变异外显率预测
  • 线段树相关算法题(5)
  • 【大语言模型 30】指令微调数据工程:高质量数据集构建
  • audioLDM模型代码阅读(二)——HiFi-GAN模型代码分析
  • 【光照】[光照模型]发展里程碑时间线
  • C++ 高并发内存池项目——无锁化设计、TLS 线程隔离与内存碎片优化
  • fork详解(附经典计算题)
  • 【系列07】端侧AI:构建与部署高效的本地化AI模型 第6章:知识蒸馏(Knowledge Distillation
  • mit6.824 2024spring Lab3A Raft
  • 简说DDPM
  • C语言---零碎语法知识补充(队列、函数指针、左移右移、任务标识符)
  • 机器人控制器开发(底层模块)——rk3588s 的 CAN 配置
  • 码农特供版《消费者权益保护法》逆向工程指北——附源码级注释与异常处理方案
  • 人工智能训练师复习题目实操题2.2.1 - 2.2.5