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

Jan*_*usz 88 android assert

我想在我的Android应用程序中使用Assert关键字在某些情况下在模拟器或测试期间的设备上销毁我的应用程序.这可能吗?

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

sco*_*awg 145

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

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

(1)通过以下方式设置系统属性"debug.assert":

adb shell setprop debug.assert 1
Run Code Online (Sandbox Code Playgroud)

只要您在执行此操作后重新安装应用程序,我验证的工作符合预期,或者

(2)通过向dalvik VM发送命令行参数"--enable-assert",这可能不是app开发人员可能做的事情(如果我在这里错了,有人会纠正我).

基本上,存在既可以全局设置,在封装级,或者在类级使断言在该各自电平的标志.该标志默认是关闭的,因此跳过断言检查.

我在我的示例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;
  }
}

对于此代码,生成的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

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

似乎JUnit的Assert类是主要使用的类,所以使用它可能是一个安全的选择.assert关键字的灵活性是能够在开发时打开断言并将其关闭以用于传送位,而是优雅地失败.

希望这可以帮助.

  • 有没有办法在Eclipse中执行`adb shell setprop debug.assert 1`? (3认同)

Dhe*_*.S. 10

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

所以IMO,最好的选择,尤其是 如果你反对依赖junit,那就是AssertionError明确抛出如下所示:

assert x == 0 : "x = " + x;
Run Code Online (Sandbox Code Playgroud)

上述陈述的替代方案是:

Utils._assert(x == 0, "x = " + x);
Run Code Online (Sandbox Code Playgroud)

方法定义为:

public static void _assert(boolean condition, String message) {
    if (!condition) {
        throw new AssertionError(message);
    }
}
Run Code Online (Sandbox Code Playgroud)

Oracle java文档建议将其AssertionError作为可接受的替代方案.

我想你可以配置Proguard去掉这些生产代码的调用.


mar*_*inj 8

在"Android in Practice"中,建议使用:

$adb shell setprop dalvik.vm.enableassertions all
Run Code Online (Sandbox Code Playgroud)

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

dalvik.vm.enableassertions=all
Run Code Online (Sandbox Code Playgroud)


Rea*_*oid 5

这让我感到害怕,我的断言没有用,直到我在google上检查了这个问题...我放弃了简单的断言,并将使用junits断言方法.

为方便起见,我使用的是:

import static junit.framework.Assert.*;

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

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


JRL*_*JRL -7

API 提供JUnit Assert

你可以做

import static junit.framework.Assert.*;
Run Code Online (Sandbox Code Playgroud)

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

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

  • OP 要求“assert 关键字”,与 junit.framework.Assert 不同,它可以通过 JIT 进行优化。正是因为这个原因,我来到了这里。希望其他一些答案会更有帮助。 (51认同)
  • 我讨厌粗鲁,但这不应该是公认的答案,因为它没有回答问题(我同意@Martin 的评论)。其他答案解释了如何使assert关键字正常工作,例如运行“adb shell setprop debug.assert 1” (27认同)
  • 被否决是因为OP询问了assert关键字。@scorpiodawg 概述了以下流程:http://stackoverflow.com/a/5563637/484261 (3认同)