我可以在 Android 设备上使用断言吗?
我想使用 Assert 关键字在我的 Android 应用程序中,在某些情况下会在模拟器上或在测试期间破坏我的设备上的应用程序。这可能吗?
看来模拟器只是忽略了我的断言。
I want to use the Assert keyword in my android apps to destroy my app in some cases on the emulator, or my device during testing. Is this possible?
It seems that the emulator just ignores my asserts.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
请参阅嵌入式 VM 控制文档(来自 源树,或格式良好的复制)。
基本上,Dalvik VM 默认设置为忽略断言检查,即使 .dex 字节代码包含执行检查的代码。检查断言可以通过以下两种方式之一打开:
(1)通过设置系统属性“debug.assert”:
我验证了只要您在执行此操作后重新安装应用程序即可按预期工作,或者
(2)通过发送dalvik VM 的命令行参数“--enable-assert”可能不是应用程序开发人员能够做的事情(如果我在这里错了,请有人纠正我)。
基本上,有一个标志可以在全局、包级别或类级别设置,以在相应级别启用断言。默认情况下该标志处于关闭状态,因此会跳过断言检查。
我在示例 Activity 中编写了以下代码:
对于此代码,生成的 dalvik 字节代码为(对于 Android 2.3.3):
请注意静态构造函数如何调用 Class 对象上的desiredAssertionStatus 方法并设置类范围变量$assertionsDisabled;还要注意,在 onCreate() 中,所有抛出 java.lang.AssertionError 的代码都被编译进去,但其执行取决于静态构造函数中为 Class 对象设置的 $assertionsDisabled 的值。
看来 JUnit 的 Assert 类是主要使用的类,因此使用它可能是一个安全的选择。 assert 关键字的灵活性在于能够在开发时打开断言,并在传送位时将其关闭,然后优雅地失败。
See the Embedded VM Control document (raw HTML from the source tree, or a nicely formatted copy).
Basically, the Dalvik VM is set to ignore assertion checks by default, even though the .dex byte code includes the code to perform the check. Checking assertions is turned on in one of two ways:
(1) by setting the system property "debug.assert" via:
which I verified works as intended as long as you reinstall your app after doing this, or
(2) by sending the command line argument "--enable-assert" to the dalvik VM which might not be something app developers are likely to be able to do (somebody correct me if I'm wrong here).
Basically, there is a flag that can be set either globally, at a package level, or at a class level which enables assertions at that respective level. The flag is off by default, as a result of which the assertion checks are skipped.
I wrote the following code in my sample Activity:
For this code, the dalvik byte code that is generated is (for Android 2.3.3):
Notice how the static constructor invokes the method desiredAssertionStatus on the Class object and sets the class-wide variable $assertionsDisabled; also notice that in onCreate(), all of the code to throw java.lang.AssertionError is compiled in, but its execution is contingent upon the value of $assertionsDisabled which is set for the Class object in the static constructor.
It appears that JUnit's Assert class is what is used predominantly, so it is likely a safe bet to use that. The flexibility of the assert keyword is the ability to turn on assertions at development time and turn them off for shipping bits and instead fail gracefully.
启用断言后,
assert
关键字只会抛出AssertionError
当布尔表达式为
false
时。所以在我看来,最好的选择,尤其是。如果您不愿意依赖 junit,请显式抛出
AssertionError
,如下所示:上述语句的替代方法是:
该方法定义为:
Oracle java 文档 建议抛出
AssertionError
作为可接受的替代方案。我想你可以配置 Proguard 来删除这些对生产代码的调用。
When assertions are enabled, the
assert
keyword simply throws anAssertionError
when the boolean expression isfalse
.So IMO, the best alternative, esp. if you're averse to depend on junit, is to throw an
AssertionError
explicitly as shown below:An alternative to the above statement is:
Where the method is defined as:
The Oracle java docs recommend throwing an
AssertionError
as an acceptable alternative.I guess you can configure Proguard to strip out these calls for production code.
在“Android 实践”中,建议使用:
如果此设置未保留在您的手机上,那么您可以创建 /data/local.prop 文件,其属性如下:
In "Android in Practice" it is suggested to use:
if this settings is not persisted on your phone then you can create /data/local.prop file with properties like:
我的断言不起作用,这让我很烦恼,直到我在谷歌上检查了这个问题……我放弃了简单的断言,转而使用 junits 断言方法。
为了方便起见,我使用:
import static junit.framework.Assert.*;
由于静态导入,我可以稍后编写:
assertTrue(...);而不是 Assert.assertTrue(...);
It was bugging the hell out of me, that my assertions didnt work, until I checked the issue out on google... I gave up on simple assertions and will go with junits assertion methods.
For convenience purposes I am using:
import static junit.framework.Assert.*;
Due to the static import I can later write:
assertTrue(...); instead of Assert.assertTrue(...);
如果您担心使用 JUnit 断言(或任何其他类路径)传送代码,您可以使用 ProGuard 配置选项“assumenosideeffects”,这将删除类路径,假设删除它对代码没有任何作用。
例如。
我有一个通用的调试库,我将所有测试方法放入其中,然后使用此选项将其从我发布的应用程序中删除。
这也消除了难以发现的问题:正在操作的字符串从未在发布代码中使用过。例如,如果您编写一个调试日志方法,并且在该方法中您在记录字符串之前检查调试模式,那么您仍然在构造字符串、分配内存、调用该方法,但随后选择不执行任何操作。剥离该类然后完全删除调用,这意味着只要您的字符串是在方法调用内构造的,它也会消失。
不过,请确保删除这些行确实是安全的,因为 ProGuard 不会对此进行检查。删除任何 void 返回方法就可以了,但是如果您从要删除的内容中获取任何返回值,请确保您没有将它们用于实际的操作逻辑。
If you're concerned about shipping code with the JUnit asserts in (or any other class path), you can use the ProGuard config option 'assumenosideeffects', which will strip out a class path on the assumption that removing it does nothing to the code.
Eg.
I have a common debug library I put all my testing methods in, and then use this option to strip it from my released apps.
This also removes the hard to spot problem of strings being manipulated that are never used in release code. For example if you write a debug log method, and in that method you check for debug mode before logging the string, you are still constructing the string, allocating memory, calling the method, but then opting to do nothing. Stripping the class out then removes the calls entirely, meaning as long as your string is constructed inside the method call, it goes away as well.
Make sure it is genuinely safe to just strip the lines out however, as it is done with no checking on ProGuard's part. Removing any void returning method will be fine, however if you are taking any return values from whatever you are removing, make sure you aren't using them for actual operational logic.
您可以使用断言,但需要一些工作才能可靠地使用它们。系统属性
debug.assert
不可靠;查看问题175697、65183,36786 和 17324。一种方法是将每个
assert
语句转换为任何运行时都可以处理的内容。使用 Java 编译器前面的源预处理器来执行此操作。例如,采用以下语句:对于调试构建,预处理器会将上述内容转换为
if
语句:对于生产构建,转换为空语句:
请注意,这将在构建时控制断言,与运行时(通常的做法)相反。
我找不到现成的预处理器,所以我编写了一个脚本。请参阅处理断言的部分。复制许可证位于此处。
You can use assertions, but it takes some work to use them reliably. System property
debug.assert
is unreliable; see issues 175697, 65183, 36786 and 17324.One method is to translate each
assert
statement to something any runtime can deal with. Do this with a source preprocessor in front of the Java compiler. For example, take this statement:For a debug build, your preprocessor would translate the above to an
if
statement:For a production build, to an empty statement:
Note that this would control assertions at build time, as opposed to run time (the usual practice).
I could find no ready-made preprocessor, so I scripted one. See the part dealing with assertions. Licence to copy is here.
添加到 Zulaxia 关于剥离 Junit 的答案 - Proguard 已经是 Android SDK /Eclipse 的一部分,下一页将告诉您如何启用它。
http://developer.android.com/guide/developing/tools/proguard.html
另外,上面的内容不适用于最新的默认混淆器配置,因为它使用 -dontoptimize 标志,必须删除该标志并打开一些优化。
To add to Zulaxia's answer on stripping out Junit - Proguard is already part of Android SDK /Eclipse and the following page tells you how to enable it.
http://developer.android.com/guide/developing/tools/proguard.html
Also the above wont work with the latest default proguard configuration because it uses the -dontoptimize flag which must be taken out and some of the optimizations turned on.
使用标准 Java assert 关键字,例如:
为此,您必须向 /system/build.prop 添加一行,然后重新启动手机:
这将在已 root 的手机上运行。使用一些能够编辑 build.prop 的文件管理器(例如 X-plore)。
优点:大多数(全部?)Android 手机都禁用了断言。即使您的代码意外断言为 false,应用程序也不会中断或崩溃。
但是,在您的开发设备上,您会遇到断言异常。
Use standard Java assert keyword, for example:
For this to work, you have to add one line to /system/build.prop, and reboot phone:
This would work on rooted phone. Use some file manager capable to edit build.prop (e.g. X-plore).
Pluses: most (all?) Android phones ship with assertions disabled. Even if your code accidentally asserts to false, app won't interrupt or crash.
However, on your development device you'll get assertion exception.
该 API 提供 JUnit 断言。
您现在可以
使用 junit 框架中提供的所有函数,如assertTrue、assertEquals、assertNull。
注意不要通过eclipse导入Junit4框架,那将是org.junit包。您必须使用 junit.framework 包才能使其在 Android 设备或模拟器上运行。
The API provides the JUnit Assert.
You can do
now you can use all the functions like assertTrue, assertEquals, assertNull that are provided in the junit framework.
Be careful not to import the Junit4 framework through eclipse, that would be the org.junit package. You have to use the junit.framework package to get it working on an android device or the emulator.