├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── it │ │ └── uncle │ │ └── androidassert │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── it │ │ │ └── uncle │ │ │ └── androidassert │ │ │ ├── AssertCase.java │ │ │ ├── MainActivity.java │ │ │ ├── MyApp.java │ │ │ └── TestActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── activity_test.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── it │ └── uncle │ └── androidassert │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── assumenosideeffects.png ├── debug-release.png └── no-assumenosideeffects.png ├── lib-android-assert ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── it │ │ └── uncle │ │ └── lib │ │ └── androidassert │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── it │ │ │ └── uncle │ │ │ └── lib │ │ │ └── util │ │ │ ├── AndroidAssert.java │ │ │ └── ThreadTypeUtil.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── it │ └── uncle │ └── lib │ └── androidassert │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | /.idea/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [ ![Download](https://api.bintray.com/packages/vectorzeng/maven/android-assert/images/download.svg?version=0.0.2) ](https://bintray.com/vectorzeng/maven/android-assert/0.0.2/link) 4 | 5 | - [x] 一、简介 6 | - [x] 二、什么是断言,什么情况下应该使用androidAssert? 7 | - [x] 三、在release版本中移除断言代码,只在debug中保留 8 | - [x] 四、集成AndroidAssert库 9 | - [x] 五、API 10 | 11 | 12 | 13 | [blog](https://juejin.im/post/5ed670e56fb9a047a96a7c9f) 14 | 15 | [readme中的截图不显示的话,点这里](https://juejin.im/post/5ed670e56fb9a047a96a7c9f) 16 | 17 | 18 | 19 | ## 一、简介 20 | 21 | > android-assert是一个非常简单轻量的android断言库。类似于junit的Assert类。 22 | > 23 | > android-assert不是用来写测试用例的,可以直接在项目代码中使用他。 24 | > 25 | > 在debug模式下,断言失败将会抛出断言异常 AssertionFailedError,在release模式下,将不会抛出异常。 26 | 27 | 28 | 29 | ## 二、什么是断言,什么情况下应该使用androidAssert? 30 | 31 | 通常断言(assert)是用在单元测试,用来校验函数返回的结果。用在自动化测试用来校验程序运行结果。 32 | 33 | 但是我们接下来要讨论的并不是单元测试中使用断言,而是在项目业务代码中使用断言。 34 | 35 | 我们一起来看几个,大家非常熟悉的例子。这些情况下使用断言会让代码更加优雅,更加健壮。 36 | 37 | 38 | 39 | ### 例子1,writeFile 40 | 41 | ```java 42 | /** 43 | * 我们希望只在子线程中调用writeFile(),主线程中调用可能会导致ui卡顿或者anr。 44 | * 45 | * 如果在主线程调用writeFile(),我们打印日志警告开发者 46 | */ 47 | public void writeFile() { 48 | //主线程,打印日志警告开发者 49 | if(!ThreadTypeUtil.isSubThread()){ 50 | Log.e(TG, "you should call writeFile at sub thread"); 51 | } 52 | // write file ... 53 | } 54 | ``` 55 | 56 | 当出现有开发人员,尝试在主线程中调用writeFile()方法时,我们通过 **日志警告** ,开发者。但是,日志提示很弱,往往会被开发者忽略掉。 57 | 58 | **于是我们改良了下代码:** 59 | 60 | ```java 61 | public void writeFile() { 62 | //debug版本,主线程中调用 writeFile ,直接抛出异常中断程序运行 63 | if(!ThreadTypeUtil.isSubThread()){ 64 | if(BuildConfig.DEBUG) { 65 | throw new RuntimeException("you should call writeFile at sub thread"); 66 | } 67 | } 68 | // write file ... 69 | } 70 | ``` 71 | 72 | 当程序员企图在主线程中调用writeFile(),在debug模式下,我们直接抛出异常,让程序崩溃。以中断他的开发。强制他优化代码。 73 | 74 | 我们引入断言库,**继续改造代码,让代码更简洁漂亮:** 75 | 76 | ```java 77 | /** 78 | * 在debug模式,下将直接抛出异常 AssertionFailedError。让开发者 79 | * 在release模式,不会抛出异常,会正常执行writeFile()函数。 80 | */ 81 | public void writeFile() { 82 | AndroidAssert.assertSubThread(); 83 | // write file ... 84 | Log.i(TG, "writeFile..."); 85 | } 86 | ``` 87 | 88 | AndroidAssert.assertSubThread()断言为子线程的意思是,**断定当前线程一定是子线程,如果不是,那么抛出异常 AssertionFailedError**。 89 | 90 | 91 | 92 | **继续优化** 93 | 94 | > 只有在debug版本,AndroidAssert 类,才有用; 95 | > 96 | > 在release版本的apk上,**能否把 AndroidAssert 相关调用的代码删除?** 97 | > 98 | > 我们先挖个坑,把例子讲完,再将release删除代码的方法。大家先忍一忍。 99 | 100 | 101 | 102 | 103 | 104 | ### 例子2,updateUI 105 | 106 | ```java 107 | /** 108 | * 在release版本,如果在子线程中调用updateUI,我们直接return,不做ui更新操作。 109 | * 但是在debug版本,如果在子线程中调用updateUI,直接出异常,让开发者发现异常调用并解决。 110 | */ 111 | public void updateUI() { 112 | boolean isMainThread = ThreadTypeUtil.isMainThread(); 113 | if (!isMainThread) { 114 | AndroidAssert.fail("updateUI must be called at main thread"); 115 | return; 116 | } 117 | //update ui .... 118 | Log.i(TG, "updateUI..."); 119 | } 120 | ``` 121 | 122 | 123 | 124 | ### 例子3,startMainActivity 125 | 126 | ```java 127 | /** 128 | * 断言context为非空,如果为null,debug模式下抛出异常 AssertionFailedError 129 | */ 130 | public void startMainActivity(Context context) { 131 | AndroidAssert.assertNotNull("context must not null", context); 132 | if (context == null) { 133 | return; 134 | } 135 | //startMainActivity... 136 | Log.i(TG, "startMainActivity..."); 137 | } 138 | ``` 139 | 140 | 141 | 142 | ## 三、我们继续改良,例子1,在release版本中移除断言代码,只在debug中保留 143 | 144 | > 只有在debug版本,AndroidAssert 类,才有用; 145 | > 146 | > 在release版本的apk上,**能否把 AndroidAssert 相关调用的代码删除?** 147 | > 148 | > 或者说打包的时候,把 AndroidAssert 相关的调用的代码 和 AndroidAssert类的代码 全部删除,再打包。 149 | 150 | 于是我想到了proguard。 151 | 152 | 在proguard中添加如下配置即可: 153 | 154 | ```pro 155 | # -dontoptimize ## 注意注意注意,proguard中配置dontoptimize;将会导致proguard不做代码优化,不会删除AndroidAssert类 156 | -assumenosideeffects class com.it.uncle.lib.util.AndroidAssert{ 157 | public *; 158 | } 159 | ``` 160 | 161 | 注意,注意,千万注意:**不能开-dontoptimize,开了,-assumenosideeffects将失效** 162 | 163 | 164 | 165 | 对assumenosideeffects用法有疑惑的可以,看下这篇blog:https://blog.csdn.net/jiese1990/article/details/21752159 166 | 167 | 以及官方wiki:https://www.guardsquare.com/en/products/proguard/manual/usage#assumenosideeffects 168 | 169 | 170 | 171 | **校验assumenosideeffects是否生效** 172 | 173 | 1. 配置成功后,打包在mapping中搜索:com.it.uncle.lib.util.AndroidAssert 174 | 175 | proguard未配置 -assumenosideeffects 的mapping.txt文件 176 | 177 | ![no-assumenosideeffects](img/no-assumenosideeffects.png) 178 | 179 | 180 | 181 | proguard配置了 -assumenosideeffects 的mapping.txt文件: 182 | 183 | ![assumenosideeffects](img/assumenosideeffects.png) 184 | 185 | 186 | 187 | 188 | 189 | 2. 反编译debug和release包对比。 190 | 191 | 比如,我们demo里的[TestActivity](app/src/main/java/com/it/uncle/androidassert/TestActivity.java) 192 | 193 | ```java 194 | public class TestActivity extends MainActivity { 195 | 196 | @Override 197 | protected void onCreate(@Nullable Bundle savedInstanceState) { 198 | super.onCreate(savedInstanceState); 199 | setContentView(R.layout.activity_test); 200 | 201 | AndroidAssert.assertNotNull(getIntent()); 202 | } 203 | } 204 | ``` 205 | 206 | 我们分别反编译debug和release包,找到TestActivity类的代码对比: 207 | 208 | ![image-20200531183510001](img/debug-release.png) 209 | 210 | 211 | 212 | 213 | 214 | ## 四、集成AndroidAssert库 215 | 216 | - gradle引入 217 | 218 | ```gradle 219 | implementation 'com.ituncle:android-assert:0.0.2' 220 | ``` 221 | 222 | - 初始化sdk,尽早调用,建议在Application#onCreate的时候调用。 223 | 224 | ```java 225 | //初始化----断言失败时,是否抛出异常 226 | AndroidAssert.enableThrowError(BuildConfig.DEBUG);//我们设置为debug模式下,断言失败才抛出异常 227 | ``` 228 | 229 | - 添加proguard,在开启混淆的版本中,移除AndroidAssert的代码 230 | 231 | ```pro 232 | # -dontoptimize ## 注意注意注意,proguard中配置dontoptimize;将会导致proguard不做代码优化,不会删除AndroidAssert类 233 | -assumenosideeffects class com.it.uncle.lib.util.AndroidAssert{ 234 | public *; 235 | } 236 | ``` 237 | 238 | 239 | 240 | ## 无、API 241 | 242 | ```java 243 | public class AndroidAssert { 244 | 245 | /** 246 | * 尽早调用,建议在Application#onCreate的时候调用。 247 | * 248 | * @param enable 当断言失败时,是否抛出异常 AssertionFailedError 249 | */ 250 | public static void enableThrowError(boolean enable){} 251 | 252 | /** 253 | * 断言失败,抛出断言异常 254 | */ 255 | public static void fail(){} 256 | public static void fail(String message){} 257 | 258 | 259 | /////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ thread ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 260 | 261 | /** 262 | * 检查当前是否是子线程,如果不是,抛出断言异常 263 | */ 264 | public static void assertSubThread() {} 265 | 266 | /** 267 | * 检查当前是否是主线程,如果不是,抛出断言异常 268 | */ 269 | public static void assertMainThread() {} 270 | 271 | 272 | /////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ null or nunNull ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 273 | 274 | /** 275 | * 检查object是否为为非空,如果为空,抛出断言异常 276 | */ 277 | public static void assertNotNull(Object object) {} 278 | public static void assertNotNull(String message, Object object) {} 279 | 280 | /** 281 | * 检查object是否为null,如果不是null,抛出断言异常 282 | */ 283 | public static void assertNull(Object object) {} 284 | public static void assertNull(String message, Object object) {} 285 | 286 | 287 | 288 | /////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ true or false ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 289 | 290 | /** 291 | * @param condition 不是true,将抛出断言异常 292 | */ 293 | public static void assertTrue(boolean condition) { 294 | assertTrue(null, condition); 295 | } 296 | public static void assertTrue(String message, boolean condition) {} 297 | 298 | /** 299 | * @param condition 不是false,将抛出断言异常 300 | */ 301 | public static void assertFalse(boolean condition) {} 302 | public static void assertFalse(String message, boolean condition) {} 303 | 304 | 305 | 306 | /////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ same ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 307 | /** 308 | * expected == actual为false,抛出断言异常 309 | */ 310 | public static void assertSame(Object expected, Object actual) {} 311 | public static void assertSame(String message, Object expected, Object actual) {} 312 | 313 | /** 314 | * object != actual为false,抛出断言异常 315 | */ 316 | public static void assertNotSame(Object expected, Object actual) {} 317 | public static void assertNotSame(String message, Object expected, 318 | Object actual) {} 319 | 320 | 321 | /////// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ equals ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 322 | 323 | /** 324 | * 检查expected、actual两个对象equals是否为true,如果为false那么抛出断言异常 325 | */ 326 | public static void assertEquals(Object expected, Object actual) {} 327 | public static void assertEquals(String message, Object expected, 328 | Object actual) {} 329 | public static void assertEquals(boolean expected, boolean actual) {} 330 | public static void assertEquals(byte expected, byte actual) {} 331 | public static void assertEquals(char expected, char actual) {} 332 | public static void assertEquals(int expected, int actual) {} 333 | // ... 334 | } 335 | ``` 336 | 337 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | compileSdkVersion 28 9 | defaultConfig { 10 | applicationId "com.it.uncle.androidassert" 11 | minSdkVersion 19 12 | targetSdkVersion 28 13 | versionCode 1 14 | versionName "1.0" 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled true 20 | signingConfig signingConfigs.debug 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | compileOptions { 25 | sourceCompatibility = 1.8 26 | targetCompatibility = 1.8 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation 'androidx.appcompat:appcompat:1.0.2' 34 | implementation 'androidx.core:core-ktx:1.0.2' 35 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 36 | implementation project(path: ':lib-android-assert') 37 | // implementation 'com.ituncle:android-assert:0.0.1' 38 | 39 | 40 | testImplementation 'junit:junit:4.12' 41 | androidTestImplementation 'androidx.test:runner:1.1.1' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # -dontoptimize ## 注意注意注意,不要加添加这个配置;将会关闭优化,导致日志语句不会被优化掉。 24 | -assumenosideeffects class com.it.uncle.lib.util.AndroidAssert{ 25 | public *; 26 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/it/uncle/androidassert/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.it.uncle.androidassert 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.it.uncle.androidassert", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/it/uncle/androidassert/AssertCase.java: -------------------------------------------------------------------------------- 1 | package com.it.uncle.androidassert; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | 7 | import com.it.uncle.lib.util.AndroidAssert; 8 | import com.it.uncle.lib.util.ThreadTypeUtil; 9 | 10 | public class AssertCase { 11 | private static final String TG = "vz-AssertCase"; 12 | 13 | 14 | // /** 15 | // * 我们希望只在子线程中调用writeFile(),主线程中调用可能会导致ui卡顿或者anr。 16 | // * 17 | // * 如果在主线程调用writeFile(),我们打印日志警告开发者 18 | // */ 19 | // public void writeFile() { 20 | // //主线程,打印日志警告开发者 21 | // if(!ThreadTypeUtil.isSubThread()){ 22 | // Log.e(TG, "you should call writeFile at sub thread"); 23 | // } 24 | // // write file ... 25 | // Log.i(TG, "writeFile..."); 26 | // } 27 | 28 | // /** 29 | // * 我们希望只在子线程中调用writeFile(),主线程中调用可能会导致ui卡顿或者anr。 30 | // * 31 | // * 如果在主线程调用writeFile(),debug模式下,我们抛出异常 32 | // */ 33 | // public void writeFile() { 34 | // //debug版本,主线程中调用 writeFile ,直接抛出异常中断程序运行 35 | // if(!ThreadTypeUtil.isSubThread()){ 36 | // if(BuildConfig.DEBUG) { 37 | // throw new RuntimeException("you should call writeFile at sub thread"); 38 | // } 39 | // 40 | // } 41 | // // write file ... 42 | // Log.i(TG, "writeFile..."); 43 | // } 44 | 45 | /** 46 | * 我们希望只在子线程中writeFile(),如果在主线程中调用会导致ui卡顿或者anr。 47 | *

48 | * 如果在主线程调用writeFile(); 49 | * 在debug模式,下将直接抛出异常 AssertionFailedError。让开发者 50 | * 在release模式,不会抛出异常,会正常执行writeFile()函数。 51 | */ 52 | public void writeFile() { 53 | AndroidAssert.assertSubThread(); 54 | // write file ... 55 | Log.i(TG, "writeFile..."); 56 | } 57 | 58 | 59 | /** 60 | * 更新UI操作必须在主线程中执行,否则将会引发crash或者界面异常。 61 | *

62 | * 在release版本,如果在子线程中调用updateUI,我们直接return,不做ui更新操作。 63 | * 但是在debug模式,如果在子线程中调用updateUI,直接出异常,让开发者发现异常调用并解决。 64 | */ 65 | public void updateUI() { 66 | boolean isMainThread = ThreadTypeUtil.isMainThread(); 67 | if (!isMainThread) { 68 | AndroidAssert.fail("updateUI must be called at main thread"); 69 | return; 70 | } 71 | //update ui .... 72 | Log.i(TG, "updateUI..."); 73 | } 74 | 75 | /** 76 | * 断言context为非空,如果为null,debug模式下抛出异常 AssertionFailedError 77 | */ 78 | public void startTestActivity(Context context) { 79 | AndroidAssert.assertNotNull("context must not null", context); 80 | if (context == null) { 81 | return; 82 | } 83 | context.startActivity(new Intent(context, TestActivity.class)); 84 | Log.i(TG, "startTestActivity..."); 85 | } 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/it/uncle/androidassert/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.it.uncle.androidassert; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | 7 | import androidx.annotation.Nullable; 8 | 9 | import com.it.uncle.lib.util.AndroidAssert; 10 | 11 | public class MainActivity extends Activity { 12 | private static final String TG = "vz-MainActivity"; 13 | 14 | @Override 15 | protected void onCreate(@Nullable Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | //初始化----断言失败时,是否抛出异常,默认不抛出异常 18 | AndroidAssert.enableThrowError(BuildConfig.DEBUG);//我们设置为debug模式下,断言失败才抛出异常 19 | 20 | setContentView(R.layout.activity_main); 21 | 22 | findViewById(R.id.btn_updateUIAtMainThread).setOnClickListener(v -> { 23 | Log.e(TG, "btn_assertMainThread"); 24 | new AssertCase().updateUI();//正常执行 25 | }); 26 | 27 | findViewById(R.id.btn_updateUIAtSubThread).setOnClickListener(v -> { 28 | Log.e(TG, "btn_assertSubThread"); 29 | new Thread(){ 30 | @Override 31 | public void run() { 32 | //在debug模式下,会抛出异常AssertionFailedError 33 | new AssertCase().updateUI(); 34 | } 35 | }.start(); 36 | 37 | }); 38 | 39 | findViewById(R.id.btn_writeFileAtMainThread).setOnClickListener(v -> { 40 | //在debug模式下,会抛出异常AssertionFailedError 41 | new AssertCase().writeFile(); 42 | }); 43 | 44 | findViewById(R.id.btn_startTestActivity).setOnClickListener(v -> { 45 | new AssertCase().startTestActivity(v.getContext()); 46 | }); 47 | 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/it/uncle/androidassert/MyApp.java: -------------------------------------------------------------------------------- 1 | package com.it.uncle.androidassert; 2 | 3 | import android.app.Application; 4 | 5 | import com.it.uncle.lib.util.AndroidAssert; 6 | 7 | public class MyApp extends Application { 8 | 9 | @Override 10 | public void onCreate() { 11 | super.onCreate(); 12 | //初始化----断言失败时,是否抛出异常,默认不抛出异常 13 | // AndroidAssert.enableThrowError(BuildConfig.DEBUG);//我们设置为debug模式下,断言失败才抛出异常 14 | AndroidAssert.enableThrowError(true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/it/uncle/androidassert/TestActivity.java: -------------------------------------------------------------------------------- 1 | package com.it.uncle.androidassert; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.Nullable; 6 | 7 | import com.it.uncle.lib.util.AndroidAssert; 8 | 9 | public class TestActivity extends MainActivity { 10 | 11 | @Override 12 | protected void onCreate(@Nullable Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_test); 15 | 16 | AndroidAssert.assertNotNull(getIntent()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 |