我可以在 Android 设备上使用断言吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2364910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:33:58  来源:igfitidea点击:

Can I use assert on Android devices?

androidassert

提问by Janusz

I want to use the Assertkeyword in my android apps to destroy my app in some cases on the emulator, or my device during testing. Is this possible?

在某些情况下,我想在我的 android 应用程序中使用Assert关键字在模拟器或我的设备上销毁我的应用程序。这可能吗?

It seems that the emulator just ignores my asserts.

模拟器似乎只是忽略了我的断言。

采纳答案by JRL

The API provides the JUnit Assert.

API 提供了JUnit Assert

You can do

你可以做

import static junit.framework.Assert.*;

now you can use all the functions like assertTrue, assertEquals, assertNull that are provided in the junit framework.

现在您可以使用 junit 框架中提供的所有函数,如 assertTrue、assertEquals、assertNull。

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.

注意不要通过 eclipse 导入 Junit4 框架,那将是 org.junit 包。您必须使用 junit.framework 包才能使其在 android 设备或模拟器上运行。

回答by scorpiodawg

See the Embedded VM Control document (raw HTML from the source tree, or a nicely formattedcopy).

请参阅嵌入式 VM 控制文档(源代码树中的原始 HTML ,或格式良好的副本)。

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:

基本上,默认情况下 Dalvik VM 设置为忽略断言检查,即使 .dex 字节代码包含执行检查的代码。检查断言通过以下两种方式之一打开:

(1) by setting the system property "debug.assert" via:

(1) 通过设置系统属性“debug.assert”:

adb shell setprop debug.assert 1

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).

(2) 通过将命令行参数“--enable-assert”发送到 dalvik VM,这可能不是应用程序开发人员可能能够做到的(如果我在这里错了,有人纠正我)。

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:

我在示例活动中编写了以下代码:


public class AssertActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    int x = 2 + 3;
    assert x == 4;
  }
}

For this code, the dalvik byte code that is generated is (for Android 2.3.3):

对于此代码,生成的 dalvik 字节代码为(对于 Android 2.3.3):


// Static constructor for the class
000318:                                        |[000318] com.example.asserttest.AssertActivity.:()V
000328: 1c00 0300                              |0000: const-class v0, Lcom/example/asserttest/AssertActivity; // class@0003
00032c: 6e10 0c00 0000                         |0002: invoke-virtual {v0}, Ljava/lang/Class;.desiredAssertionStatus:()Z // method@000c
000332: 0a00                                   |0005: move-result v0
000334: 3900 0600                              |0006: if-nez v0, 000c // +0006
000338: 1210                                   |0008: const/4 v0, #int 1 // #1
00033a: 6a00 0000                              |0009: sput-boolean v0, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
00033e: 0e00                                   |000b: return-void
000340: 1200                                   |000c: const/4 v0, #int 0 // #0
000342: 28fc                                   |000d: goto 0009 // -0004

: :

// onCreate() 00035c: |[00035c] com.example.asserttest.AssertActivity.onCreate:(Landroid/os/Bundle;)V 00036c: 6f20 0100 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0001 000372: 1501 037f |0003: const/high16 v1, #int 2130903040 // #7f03 000376: 6e20 0500 1200 |0005: invoke-virtual {v2, v1}, Lcom/example/asserttest/AssertActivity;.setContentView:(I)V // method@0005 00037c: 1250 |0008: const/4 v0, #int 5 // #5 00037e: 6301 0000 |0009: sget-boolean v1, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000 000382: 3901 0b00 |000b: if-nez v1, 0016 // +000b 000386: 1251 |000d: const/4 v1, #int 5 // #5 000388: 3210 0800 |000e: if-eq v0, v1, 0016 // +0008 00038c: 2201 0c00 |0010: new-instance v1, Ljava/lang/AssertionError; // class@000c 000390: 7010 0b00 0100 |0012: invoke-direct {v1}, Ljava/lang/AssertionError;.:()V // method@000b 000396: 2701 |0015: throw v1 000398: 0e00 |0016: return-void

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.

注意静态构造函数如何调用 Class 对象上的 desiredAssertionStatus 方法并设置类范围变量 $assertionsDisabled; 还要注意,在 onCreate() 中,所有抛出 java.lang.AssertionError 的代码都被编译进去了,但它的执行取决于 $assertionsDisabled 的值,该值是在静态构造函数中为 Class 对象设置的。

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.

似乎 JUnit 的 Assert 类是主要使用的类,因此使用它可能是一个安全的赌注。assert 关键字的灵活性在于能够在开发时打开断言并在传送位时关闭它们,而不是优雅地失败。

Hope this helps.

希望这可以帮助。

回答by Dheeraj Vepakomma

When assertions are enabled, the assertkeyword simply throws an AssertionErrorwhen the boolean expression is false.

启用断言时,assert关键字只会AssertionError在布尔表达式为 时抛出false

So IMO, the best alternative, esp. if you're averse to depend on junit, is to throw an AssertionErrorexplicitly as shown below:

所以 IMO,最好的选择,尤其是。如果您不愿意依赖junit,则AssertionError明确抛出如下所示:

assert x == 0 : "x = " + x;

An alternative to the above statement is:

上述声明的替代方案是:

Utils._assert(x == 0, "x = " + x);

Where the method is defined as:

其中方法定义为:

public static void _assert(boolean condition, String message) {
    if (!condition) {
        throw new AssertionError(message);
    }
}

The Oracle java docs recommendthrowing an AssertionErroras an acceptable alternative.

Oracle java 文档建议将 anAssertionError作为可接受的替代方案。

I guess you can configure Proguard to strip out these calls for production code.

我想你可以配置 Proguard 来去除这些对生产代码的调用。

回答by marcinj

In "Android in Practice" it is suggested to use:

在“Android in Practice”中,建议使用:

$adb shell setprop dalvik.vm.enableassertions all

if this settings is not persisted on your phone then you can create /data/local.prop file with properties like:

如果此设置未保留在您的手机上,则您可以使用以下属性创建 /data/local.prop 文件:

dalvik.vm.enableassertions=all

回答by Ready4Android

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.

直到我在 google 上检查了这个问题之前,我的断言都让我很恼火……我放弃了简单的断言,将使用 junits 断言方法。

For convenience purposes I am using:

为方便起见,我使用:

import static junit.framework.Assert.*;

导入静态 junit.framework.Assert.*;

Due to the static import I can later write:

由于静态导入,我以后可以写:

assertTrue(...); instead of Assert.assertTrue(...);

assertTrue(...); 而不是 Assert.assertTrue(...);

回答by Zulaxia

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.

如果您担心在(或任何其他类路径)中带有 JUnit 断言的代码,您可以使用 ProGuard 配置选项 'assumenosideeffects',它会删除类路径,假设删除它对代码没有任何影响.

Eg.

例如。

-assumenosideeffects junit.framework.Assert {
*;
}

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.

但是,请确保仅去除线条是真正安全的,因为它是在没有检查 ProGuard 的情况下完成的。删除任何 void 返回方法都可以,但是如果您从要删除的任何内容中获取任何返回值,请确保您没有将它们用于实际操作逻辑。

回答by Michael Allan

You can use assertions, but it takes some work to use them reliably. System property debug.assertis unreliable; see issues 175697, 65183, 36786and 17324.

您可以使用断言,但需要一些工作才能可靠地使用它们。系统属性debug.assert不可靠;请参阅问题175697651833678617324

One method is to translate each assertstatement to something any runtime can deal with. Do this with a source preprocessor in front of the Java compiler. For example, take this statement:

一种方法是将每个assert语句转换为任何运行时都可以处理的内容。使用 Java 编译器前面的源预处理器来执行此操作。例如,采取以下声明:

assert x == 0: "Failure message";

For a debug build, your preprocessor would translate the above to an ifstatement:

对于调试版本,您的预处理器会将上述内容转换为if语句:

{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }

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.

我找不到现成的预处理器,所以我编写了一个. 请参阅处理断言的部分。复制许可证在这里

回答by Sean Moore

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.

添加到 Zulaxia 关于剥离 Junit 的答案 - Proguard 已经是 Android SDK /Eclipse 的一部分,以下页面告诉您如何启用它。

http://developer.android.com/guide/developing/tools/proguard.html

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.

此外,上述内容不适用于最新的默认 proguard 配置,因为它使用了 -dontoptimize 标志,必须删除该标志并打开一些优化。

回答by Pointer Null

Use standard Java assertkeyword, for example:

使用标准的 Java assert关键字,例如:

assert a==b;

For this to work, you have to add one line to /system/build.prop, and reboot phone:

为此,您必须在 /system/build.prop 中添加一行,然后重启手机:

debug.assert=1

This would work on rooted phone. Use some file manager capable to edit build.prop (e.g. X-plore).

这将适用于有根电话。使用一些能够编辑 build.prop 的文件管理器(例如 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.

优点:大多数(全部?)Android 手机都禁用了断言。即使您的代码意外断言为 false,应用程序也不会中断或崩溃。但是,在您的开发设备上,您将收到断言异常。