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

3pvhb19x  于 2022-12-28  发布在  Android
关注(0)|答案(9)|浏览(223)

我想在我的安卓应用中使用**Assert**关键字来销毁模拟器上的应用,或者在测试期间销毁我的设备。
模拟器似乎忽略了我的Assert。

ctrmrzij

ctrmrzij1#

请参阅嵌入式VM控件文档(source tree的原始HTML或nicely formatted副本)。
基本上,Dalvik VM默认设置为忽略Assert检查,即使.dex字节码包含执行检查的代码。检查Assert有两种方式:
(1)通过以下方式设置系统属性“debug.assert”:

adb shell setprop debug.assert 1

我已验证,只要您在执行此操作后重新安装应用程序,它就能按预期工作,或者
(2)通过向dalvik VM发送命令行参数“--enable-assert”,这可能不是应用程序开发人员能够做到的(如果我说错了,请纠正我)。
基本上,有一个标志可以在全局、包级或类级设置,它在相应的级别启用Assert。该标志默认为关闭,因此跳过Assert检查。
我在示例活动中编写了以下代码:

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的代码都被编译了,但是它的执行取决于$assertionsDisabled的值,该值是为静态构造函数中的Class对象设置的。
JUnit的Assert类似乎是主要使用的类,因此使用它可能是一个安全的选择。assert关键字的灵活性在于能够在开发时打开Assert,并在发送位时关闭Assert,而不是优雅地失败。

5ssjco0h

5ssjco0h2#

当Assert被启用时,如果布尔表达式是false,则assert关键字只抛出AssertionError
因此,最好的替代方法,特别是如果你不愿意依赖junit,就是显式地抛出一个AssertionError,如下所示:

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

上述陈述的替代方法是:

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

其中方法定义为:

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

Oracle java文档recommend抛出AssertionError作为可接受的替代方案。
我想您可以配置Profuard来去除这些对产品代码的调用。

qmelpv7a

qmelpv7a3#

在“Android实践”中,建议用途:

$adb shell setprop dalvik.vm.enableassertions all

如果此设置未保留在电话上,则可以创建/data/local.prop文件,其属性如下:

dalvik.vm.enableassertions=all
doinxwow

doinxwow4#

我的Assert不起作用,这让我很恼火,直到我在谷歌上检查了这个问题......我放弃了简单的Assert,将使用junitsAssert方法。
为方便起见,我使用:
导入静态junit. framework. assert. *;
由于静态导入,我可以稍后编写:
Assert正确(...);而不是Assert。assertTrue(...);

camsedfj

camsedfj5#

如果您担心在(或任何其他类路径)中发布带有JUnitAssert的代码,可以使用ProGuard配置选项'assunosideeffects',该选项将剥离类路径,前提是删除类路径对代码没有任何影响。
例如:

-assumenosideeffects junit.framework.Assert {
*;
}

我有一个公共调试库,我把我所有的测试方法,然后使用这个选项,以剥离它从我发布的应用程序。
这也消除了在发布代码中从未使用过的字符串被操纵的难以发现的问题。例如,如果你编写了一个调试日志方法,并且在记录字符串之前在该方法中检查调试模式,你仍然在构造字符串、分配内存、调用方法,但是随后选择不做任何事情。剥离类然后完全删除调用。这意味着只要字符串是在方法调用中构造的,它也会消失。
但是要确保仅仅去掉这些行是真正安全的,因为这是在没有检查ProGuard的情况下完成的。删除任何void返回方法都是可以的,但是如果你要从任何你要删除的方法中获取任何返回值,请确保你没有将它们用于实际的操作逻辑。

fykwrbwg

fykwrbwg6#

您可以使用Assert,但是可靠地使用它们需要一些工作:系统属性debug.assert是不可靠的;请参见第175697651833678617324期。
一种方法是将每个assert语句转换为任何运行时都能处理的内容,在Java编译器前面使用源代码预处理器来完成此操作,例如,使用以下语句:

assert x == 0: "Failure message";

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

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

对于生产版本,为空语句:

;

注意,这将在构建时控制Assert,而不是在运行时(通常的做法)。
我找不到现成的预处理器,所以我使用了scripted one。参见处理Assert的部分。复制许可证是here

qqrboqgw

qqrboqgw7#

为了补充Zulaxia关于剥离Junit的回答,Profuard已经是Android SDK /Eclipse的一部分,下一页将告诉您如何启用它。
http://developer.android.com/guide/developing/tools/proguard.html
另外,上面的方法不适用于最新的默认proguard配置,因为它使用了-dontoptimize标志,必须删除该标志并打开一些优化。

k97glaaz

k97glaaz8#

使用标准Javaassert关键字,例如:

assert a==b;

要使其正常工作,您必须在/system/build.prop中添加一行,然后重新启动电话:

debug.assert=1

这将工作在根电话。使用一些文件管理器能够编辑建设。prop(如X-plore)。
优点:大多数(所有?)Android手机都禁用了Assert。即使你的代码意外Assert为false,应用程序也不会中断或崩溃。但是,在你的开发设备上,你会得到Assert异常。

r8uurelv

r8uurelv9#

API提供了JUnit Assert
你能做到

import static junit.framework.Assert.*;

现在你可以使用junit框架中提供的所有函数,如assertTrue、assertEquals、assertNull。
注意不要通过eclipse导入Junit4框架,那将是org.junit包,你必须使用junit.framework包才能让它在android设备或模拟器上工作。

相关问题