Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse

经常打开别人的工程,发现layout里面使用了一些第三方的自定义控件,Graphical Layout标签里是无法预览页面的,抛出一些异常,上图吧:




对于提示Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse。

或者直接抛出的java.lang.NullPointerException,我们直接找到View层的代码,然后 解决方法是定位触发错误代码段,并将造成此错误的代码行用
if(!isInEditMode()){
//造成错误的代码段
}
包起来,这样在Eclipse中显示时将跳过此代码段而不再出现错误。



这样就可以正常预览layout了。

WindowManager: Window{a06d7b0 u0 Toast} state from COMMIT_DRAW_PENDING to READY_TO_SHOW; reason: commitFinishDrawingLocked 08-05 10:18:39.918 1000 3093 3207 I WindowManager: Window{a06d7b0 u0 Toast} state from READY_TO_SHOW to HAS_DRAWN; reason: performShowLocked 08-05 10:18:39.919 1000 3093 3207 D CoreBackPreview: return markWindowHasDrawn mComposed: false mWaitTransition: false 08-05 10:18:39.919 1000 3093 3207 D ActivityTaskManager: removeStartingWindowAnimation for activity=ActivityRecord{137003130 u0 com.android.settings/.applications.InstalledAppDetails t202 f}} prepareAnimation=true,Callers=com.android.server.wm.ActivityRecord.removeStartingWindow:3390 com.android.server.wm.ActivityRecord.onFirstWindowDrawn:8033 com.android.server.wm.WindowState.performShowLocked:4910 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:402 com.android.server.wm.DisplayContent.lambda$new$8:1138 08-05 10:18:39.919 1000 3093 3207 D ActivityTaskManager: Clearing startingData for activity=ActivityRecord{137003130 u0 com.android.settings/.applications.InstalledAppDetails t202 f}} mStartingData=null mStartingSurface=null 08-05 10:18:39.919 10540 26040 26063 E TestRunner: ----- begin exception ----- 08-05 10:18:39.919 10540 26040 26063 E TestRunner: java.lang.RuntimeException: java.lang.AssertionError 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at com.android.compatibility.common.util.SystemUtil.eventually(SystemUtil.java:359) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at com.android.compatibility.common.util.SystemUtil.eventually(SystemUtil.java:332) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at android.hibernation.cts.AutoRevokeTest.testAutoRevoke_userAllowlisting(AutoRevokeTest.kt:1063) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at java.lang.reflect.Method.invoke(Native Method) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:61) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:148) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:142) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at java.util.concurrent.FutureTask.run(FutureTask.java:343) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at java.lang.Thread.run(Thread.java:1119) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: Caused by: java.lang.AssertionError 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.Assert.fail(Assert.java:87) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.Assert.assertTrue(Assert.java:42) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.Assert.assertFalse(Assert.java:65) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at org.junit.Assert.assertFalse(Assert.java:75) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at android.hibernation.cts.AutoRevokeTest$testAutoRevoke_userAllowlisting$lambda$18$lambda$17$$inlined$eventually$1.run(AutoRevokeTest.kt:752) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: at com.android.compatibility.common.util.SystemUtil.eventually(SystemUtil.java:347) 08-05 10:18:39.919 10540 26040 26063 E TestRunner: ... 11 more 08-05 10:18:39.919 10540 26040 26063 E TestRunner: ----- end exception ----- 08-05 10:18:39.919 1000 3093 3207 D DisplayModeDirector: setAppRequest displayId : 0 modeId: 1 requestedRefreshRate: 0.0 requestedMinRefreshRateRange: 0.0 requestedMaxRefreshRateRange: 120.00001 日志分析
最新发布
08-06
<think>我们正在处理两个主要问题: 1. Android WindowManager Toast状态变化日志分析 2. TestRunner测试失败原因排查 参考引用: 引用[1]提到:确保应用在Android 9上可照常运行,可能需要进行一些调整,但不需要使用新的API或更改targetSdkVersion。 引用[2]提到:如果应用定义了无障碍功能窗格标题,Service可以识别应用界面更新。TYPE_WINDOW_STATE_CHANGED事件发生时,可用getContentChangeTypes()确定窗口发生的变更,例如窗格有新标题或窗格消失。 引用[3]提到:异常处理应该向外传播以便错误原因不丢失,千万别捕获了异常什么事情都不干。 根据用户问题,我们需要: 1. 分析Toast窗口状态变化:Toast的显示和隐藏会触发窗口状态变化事件,我们可以通过监听窗口状态变化事件来跟踪Toast的状态。 2. 测试失败原因排查:通常测试失败会抛出异常,我们需要查看测试日志,特别是异常堆栈,以确定失败原因。 具体步骤: 一、Toast窗口状态变化日志分析 在Android中,Toast是通过WindowManager添加的窗口。我们可以通过AccessibilityService来监听窗口状态变化事件。 步骤: 1. 创建一个AccessibilityService,并在服务配置中监听窗口状态变化事件(TYPE_WINDOW_STATE_CHANGED)。 2. 在onAccessibilityEvent方法中,当事件类型为TYPE_WINDOW_STATE_CHANGED时,检查窗口的类名(className)是否为Toast的窗口类名(通常为"android.widget.Toast$TN")。 3. 当检测到Toast窗口出现时,记录Toast显示;当Toast窗口消失时,记录Toast隐藏。 示例代码(在AccessibilityService中): ```java @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { // 引用[2]中提到:getContentChangeTypes()可以确定窗口发生的变更,但注意,这里我们更关注窗口的类名和事件类型 AccessibilityNodeInfo source = event.getSource(); if (source != null) { CharSequence className = source.getClassName(); // 检查是否是Toast窗口 if (className != null && className.toString().equals("android.widget.Toast$TN")) { // 根据窗口是否可见来判断状态 if (source.isVisibleToUser()) { // Toast显示 Log.d("ToastMonitor", "Toast shown"); } else { // Toast隐藏 Log.d("ToastMonitor", "Toast hidden"); } } source.recycle(); } } } ``` 注意:不同Android版本Toast的实现可能不同,类名可能有差异,需要适配。 二、TestRunner测试失败原因排查 测试失败通常是由于测试用例中的断言失败或未处理的异常引起的。 步骤: 1. 查看测试运行日志,特别是失败测试的堆栈跟踪(stack trace)。 2. 根据堆栈跟踪定位到具体的测试方法和失败行。 3. 分析失败原因:可能是预期结果与实际结果不符,或者代码中出现了异常(如空指针、网络请求超时等)。 在测试代码中,我们应该确保捕获异常并正确记录,避免捕获异常后什么都不做(如引用[3]所述)。 示例:在测试中,我们应避免: ```java try { // 一些可能出错的代码 } catch (Exception e) { // 什么都不做 } ``` 而应该: ```java try { // 一些可能出错的代码 } catch (Exception e) { // 记录异常信息,然后重新抛出或者标记测试失败 Log.e("Test", "Exception occurred", e); throw e; // 或者使用AssertionError } ``` 或者使用测试框架提供的异常处理机制(如JUnit的@Test(expected=...)或Assert.assertThrows)。 另外,我们可以使用Android Studio的测试运行工具查看详细的测试报告。 相关问题: 1. 如何自定义AccessibilityService来监听特定窗口事件? 2. 如何确保在测试中正确处理异常? 3. 如何分析Android测试日志?</think>### Android WindowManager Toast状态变化日志分析 Toast的窗口状态变化可通过`WindowManager`日志分析,关键步骤如下: 1. **日志过滤**: 使用`adb logcat`命令过滤`WindowManager`标签: ```bash adb logcat | grep "WindowManager" ``` 当Toast显示/隐藏时,会输出类似日志: ```log I/WindowManager: Adding window Window{...} toast ... I/WindowManager: Removing window Window{...} toast ... ``` 2. **状态变化监听**(参考引用[2]): 通过`AccessibilityService`监听`TYPE_WINDOW_STATE_CHANGED`事件,使用`getContentChangeTypes()`检测窗口变更: ```java public class ToastMonitorService extends AccessibilityService { @Override public void onAccessibilityEvent(AccessibilityEvent event) { if (event.getEventType() == TYPE_WINDOW_STATE_CHANGED) { int changeType = event.getContentChangeTypes(); if (changeType == CONTENT_CHANGE_TYPE_PANE_APPEARED) { Log.d("Toast", "Toast显示: " + event.getSource().getPackageName()); } else if (changeType == CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) { Log.d("Toast", "Toast隐藏"); } } } } ``` 3. **常见异常分析**: - **`Token null is not valid`**:Toast在Activity销毁后调用`show()`,需确保Context存活。 - **`Unable to add window`**:权限问题(如`SYSTEM_ALERT_WINDOW`未授权)或窗口层级错误。 --- ### TestRunner测试失败原因排查 测试失败需结合日志和异常处理策略(参考引用[3]): 1. **关键日志定位**: - 过滤`TestRunner`日志: ```bash adb logcat | grep "TestRunner" ``` - 典型错误日志示例: ```log E/TestRunner: failed: testLogin(com.example.AppTest) E/AndroidRuntime: Caused by: java.lang.NullPointerException: ... ``` 2. **根本原因分析**: | **错误类型** | **排查方向** | **解决方案** | |--------------------|---------------------------------------|------------------------------------------| | `NullPointerException` | 未初始化对象或空Context | 检查Mock对象注入及生命周期 | | `IllegalStateException` | 主线程阻塞/资源竞争 | 使用`@UiThreadTest`或`CountDownLatch`同步 | | 断言失败(`AssertionError`) | 预期值与实际结果不符 | 验证数据源及模拟逻辑 | | `SecurityException` | 权限未声明(如`INTERNET`) | 在测试Manifest中添加权限 | 3. **异常处理最佳实践**: - **禁止空捕获**(引用[3]):避免`catch (Exception e) {}`,需记录或传播异常: ```java try { performCriticalOperation(); } catch (IOException e) { Log.e("Test", "IO失败: " + e.getMessage()); // 记录具体原因 throw new AssertionError("测试终止", e); // 传播异常 } ``` - **使用`TestWatcher`监听结果**(JUnit规则): ```java public class CustomWatcher extends TestWatcher { @Override protected void failed(Throwable e, Description description) { Log.d("TestFail", description + "失败: " + e); } } ``` --- ### 相关问题 1. 如何自定义`AccessibilityService`以捕获Toast的精确显示时长? 2.Android测试中,如何模拟网络故障以验证异常处理逻辑? 3. `WindowManager`日志中出现`AppToken mismatch`错误时应如何修复? [^1]: 平台变更可能影响应用行为,需调整但无需更改targetSdkVersion [^2]: 通过`getContentChangeTypes()`可检测窗格标题更新或消失 [^3]: 异常处理需避免静默捕获,应传播错误原因便于排查
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风口猪炒股指标

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值