AndroidX Lifecycle v2.1.0 在 ViewModel 中引入 viewModelScope,当 ViewModel 被销毁时它会自动取消协程任务,这个特性真的好用。...本文介绍 viewModelScope 使用和内部实现方式,分析 ViewModel 是如何自动取消协程的。...) 方法获取对象不存在时,创建一个新的 CoroutineScope 并调用 setTagIfAbsent(JOB_KEY, scope) 方法存储新建的 CoroutineScope 对象。...ViewModel 被销毁时内部会执行 clear() 方法,在 clear() 方法中遍历调用 closeWithRuntimeException 取消了 viewModelScope 的协程,实现流程非常清晰...MVVM 和协程,非常推荐在 ViewModel 中使用 viewModelScope 方式。
viewModelScope 对结构化并发 的贡献在于将一项扩展属性加入到 ViewModel 类中,从而在 ViewModel 销毁时自动地取消子协程。...当 ViewModel 被清空时,它会运行 clear() 方法进而调用如果不用 viewModelScope 我们就得重写的 onCleared() 方法。...在 clear() 方法中,ViewModel 会取消 viewModelScope 中的任务。...考虑到挂起方法自身有线程封闭机制,使用其他派发器并不合适,因为我们不想去取代 ViewModel 已有的功能。...这个方法在 Instrumented Android 测试中可用,在单元测试中不可用。
那这个ViewModel中的clear()方法又是谁调用的呢?...的get方法中调用了put,也就是说,我们在创建ViewModel的时候并把其保存了起来。...; 在ViewModelStore中也有个clear()方法,会循环调用ViewModel中的clear()方法; 而ViewModelStore中的clear()方法,是由Lifecycle在生命周期执行到...为避免有的同学没理解,我们再反推梳理一次 在生命周期执行到onDestroy的时候,调用ViewModelStore中的clear()方法; 在ViewModelStore中的clear()方法中,循环调用...ViewModel的clear()方法; 在ViewModel的clear()方法中,循环调用close()取消协程。
所以在调用函数时,有invoke-direct,invoke-virtual,另外还有invoke-static、invoke-super以及invoke-interface等几种不同的指令。...中的一个private函数,如果修改smali时错用invoke-virtual或invoke-static将在回编译后程序运行时引发一个常见的VerifyError invoke-virtual: 用于调用...;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z 刚才看到的例子都是“调用函数”这个操作而已,貌似没有取函数返回的结果的操作?...invoke-virtual {v2}, Ljava/lang/String;->length()I move-result v2 v2保存的则是调用String.length()返回的整型。...,这样可能会出现很多寄存器方面的错误导致编译失败。
. values方法 values方法的的返回值实际上就是上面$VALUES数组对象 swtich中的枚举 在Java中,switch-case是我们经常使用的流程控制语句.当枚举出来之后,switch-case...// Method com/company/Season.ordinal:()I 事实果真如此,在switch-case中,还是将Enum转成了int值(通过调用Enum.oridinal()方法) 枚举与混淆...); } 关于为什么要保留values()方法和valueOf()方法,请参考文章读懂 Android 中的代码混淆 关于枚举的部分 使用proguard优化 使用Proguard进行优化,可以将枚举尽可能的转换成...this.tagName = tagName; } public String getTag() { return tagName; } } 调用起来也更加简单 AppManager.INSTANCE.getTag...", "setColor color=" + color); } 调用的该方法的时候 setColor(Colors.GREEN); 关于Android中的枚举,可以参考探究Android中的注解 以上就是我对
中为:Ljava/lang/String;,其中java/lang对应java.lang包,String就是定义在该包中的一个对象。...PREFS_INSTALLATION_ID:Ljava/lang/String; sget-object就是用来获取变量值并保存到紧接着的参数的寄存器中,在这里,把上面出现的PREFS_INSTALLATION_ID...中的一个private函数,如果修改smali时错用invoke-virtual或invoke-static将在回编译后程序运行时引发一个常见的VerifyError(更多错误汇总可参照APK反编译之番外三...;Lcn/game189/sms/SMSListener;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z 这个是电信SDK中的付费接口...另外注意到.line这个标识,它是标注了该代码在原Java文件中的行数,它也很有用,想想使用eclipse开发时,遇到错误崩溃时,在catLog不是有提示哪个文件哪一行崩溃的么?
. values方法 values方法的的返回值实际上就是上面$VALUES数组对象 swtich中的枚举 在Java中,switch-case是我们经常使用的流程控制语句.当枚举出来之后,switch-case...// Method com/company/Season.ordinal:()I 事实果真如此,在switch-case中,还是将Enum转成了int值(通过调用Enum.oridinal()方法) 枚举与混淆...); } 关于为什么要保留values()方法和valueOf()方法,请参考文章读懂 Android 中的代码混淆 关于枚举的部分 使用proguard优化 使用Proguard进行优化,可以将枚举尽可能的转换成...this.tagName = tagName; } public String getTag() { return tagName; } } 调用起来也更加简单...", "setColor color=" + color); } 调用的该方法的时候 setColor(Colors.GREEN); 关于Android中的枚举,可以参考探究Android中的注解 以上就是我对
掌握 Kotlin Android 单元测试:MockK 框架深度实践指南在 Android 开发中,单元测试是保障代码质量的核心手段。...1.1 Kotlin 原生支持优势协程友好:直接 Mock 挂起函数(coEvery/coVerify)对象声明处理:轻松 Mock object 单例类扩展函数支持:无需特殊配置即可模拟扩展方法DSL...= ProductViewModel(repo) viewModel.loadProducts() // 使用 Turbine 库简化 Flow 测试 viewModel.products.test...} returns false```六、常见陷阱规避陷阱 1:未清理 Mock 状态@Afterfun tearDown() { unmockkAll() // 必须清理防止测试污染}陷阱 2:错误的作用域验证...或使用接口结语建议在实际项目中:从简单场景入手,逐步尝试高级功能结合 Kotlin 协程测试工具(如 runTest)定期查看 MockK 官方文档 获取更新
项目由MVP过渡到MVVM时,其中一个典型的重构手段就是将Presenter中的回调写法改写成在ViewModel中持有LiveData由View层订阅,比如以下场景: 在大力自习室中,当老师切换至互动模式时...ViewModel和View层的通信只依赖LiveData足够吗? 在使用MVVM架构时,数据变化驱动UI更新。...使用lifecycle-runtime-ktx库中的launchWhenX方法,对Channel的收集协程会在组件生命周期 时挂起,从而避免异常。...那如果是要在Fragment中调用Activity的方法,通过共享ViewModel可行吗?...MVVM并没有约束View层与ViewModel的交互方式,具体来说就是View层可以随意调用ViewModel中的方法,而MVI架构下ViewModel的实现对View层屏蔽,只能通过发送Intent
将生成的 Apk 文件使用 ApkTool 进行解包,之后在 Sublime Text 3 中打开,下面附上下载链接: 链接: https://pan.baidu.com/s/1EbZsk106YLV22TgoVkbhbw...invoke-virtual {p1}, Ljava/lang/String;->getBytes()[B // move-result-object v0 移动上一次方法调用的对象引用返回值到...(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; // move-result-object v0 移动上一次方法调用的对象引用返回值到...,我们简单看下 onClick 中如何处理: // 调用 onClick 方法 传如 View # virtual methods .method public onClick(Landroid/view...toString 方法 invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String; // 赋值 v0
4..local 0,标明在这个函数中最少要用到的本地寄存器的个数,出现在方法中的第一行。...如 .local 4,则可以使用的寄存器是v0-v3。 5.当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。...smali中的函数调用也分为direct和virtual两种类型,direct method就是private函数,public和protected函数都属于virtual method。...在调用函数时,有invoke-direct,invoke-virtual,invoke-static、invoke-super以及invoke-interface等几种不同的指令。....line 277,标注了该代码在原Java文件中的行数,它不是必须的,去掉没有编译问题。它在出错时可以指出错误位置,jd-gui[2]工具即是通过分析这些信息将smali代码还原成Java代码的。
//调用父类的方法 invoke-interface //调用接口方法 非私有实例方法的调用 invoke-virtual {参数}, 方法所属类名;->方法名(参数类型)返回值类型; 比如以下java...Object;->()V #调用父类构造方法 invoke-virtual {p0}, LTest;->getName()Ljava/lang/String;# 调用普通成员getName...p0, LTest;->a:I 删除该关键字不影响程序执行,该关键字在反编译时能很好地帮助我们阅读smali代码,以该关键字当作代码块的分割线,方便快速阅读执行内容 :cond_0 条件分支,配合if使用...,因为没有提示具体原因或者具体的行数,有可能是静态方法调用你写成了虚方法的调用,或者是构造函数调用没有加尖括号, 甚至是寄存器数量过少 等等 思考 为什么方法中包括参数在内需要3个寄存器,但是在定义的时候只写了两个却也不报错呢...# 方法调用 invoke-virtual {v0,v1},Ljava/io/PrintStream;->print(Ljava/lang/String;)V return-void .end
java方法 myMethod([I)Ljava/lang/String; String myMethod(int[])...#是smali注释 .method和.end method 类似Java大括号{} .locals 指定方法中非参寄存器总数,出现在方法第一行 .registers 指定方法中寄存器总数 ....调用private方法 invoke-virtual 调用protected或public方法 return-void 表示方法结束返回void p0 在静态方法中表示当前对象实例 p1 表示当前...; move-result-object v1 v1保存的就是调用getPreferences(int)方法返回的SharedPreferences实例 invoke-virtual {v2},...Ljava/lang/String;->length()I move-result v2 v2保存的则是调用String.length()返回的整型 注: Long和Double类型是64位,需要
,编译时,静态确定的; invoke-virtual 虚方法调用,调用的方法运行时确认实际调用,和实例引用的实际对象有关,动态确认的,一般是带有修饰符protected或public的方法; invoke-direct...没有被覆盖方法的调用,即不用动态根据实例所引用的调用,编译时,静态确认的,一般是private或方法; invoke-super 直接调用父类的虚方法,编译时,静态确认的。.../lang/System;->out:Ljava/io/PrintStream; const-string v1,"Hello World" #方法调用指令 invoke-virtual...;#定义父类 .method public static main([Ljava/lang/String;)V#声明静态main()方法 .registers 4#程序使用v0、v1、v2寄存器和一个参数寄存器.../lang/System;->out:Ljava/io/PrintStream; const-string v1, "Hello World" #构造字符串 #方法调用指令 invoke-virtual
关于intern()方法 当一个String实例str调用intern()方法时,如果常量池中已经有了这个字符串,那么直接返回常量池中它的引用,如果没有,那就将它的引用保存一份到字符串常量池,然后直接返回这个引用...可参考JDK中的解释或The Java Virtual Machine Specification, Java SE 8 Edition (§5.1),简单来说就是一个可以手动将未存在常量池的字符串存入常量池并返回其引用的方法...在StringDemo3中,执行s1.intern();时,第一次执行了ldc,此时查找字符串常量池,发现没有对应内容的String的引用,故直接使用了s1的引用。...产生差异的原因是: 在JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由StringBuilder创建的字符串实例在Java堆上...在遇到String类型常量时,resolve的过程如果发现StringTable已经有了内容匹配的java.lang.String的引用,则直接返回这个引用。
(Ljava/lang/String;)V #29 = Utf8 method2 #30 = Utf8...ACC_SYNCHRONIZED标志表示方法为同步方法,如果为非静态方法(没有ACC_STATIC标志),使用调用该方法的对象作为锁对象;如果为静态方法(有ACC_STATIC标志),使用该方法所属的Class...方法级的同步是隐式,即无需通过字节码指令来控制的,它实现在方法调用和返回操作之中。虚拟机可以从方法常量池中的方法表结构中的ACC_SYNCHRONIZED访问标志区分一个方法是否同步方法。...当方法调用时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否被设置,如果设置了,执行线程将先持有管程,然后再执行方法,最后在方法完成(无论是正常完成还是非正常完成)时释放管程。...编译器必须确保无论方法通过何种方式完成,方法中调用过的每条monitorenter指令都必须有执行其对应monitorexit指令,而无论这个方法是正常结束还是异常结束。
在 Android 中,一般是不建议直接使用 GlobalScope 的。那么,在 Android 中应该如何正确使用协程呢?再细分一点,如何直接在 Activity 中使用呢?...调用 getMessage() 方法和之前的 launchFromMainScope() 效果也是一样的,记得在 ViewModel 的 onCleared() 回调里取消协程。...添加如下依赖: implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha03" 直接在 liveData {} 代码块中调用需要异步执行的挂起函数...emit(string) } 你可能会好奇这里好像并没有任何的显示调用,那么,liveData 代码块是在什么执行的呢?...在 Activity/Fragment 等生命周期组件中我们可以很方便的使用,但是在 MVVM 中又不会过多的在 View 层进行逻辑处理,viewModelScope 基本就可以满足 ViewModel
" .method public static log(Ljava/lang/String;)V .locals 1 .prologue const-string...2.将加密的response放到数组中,然后在一个onclick中执行for循环,调用unmashall()(unmashall函数是调用decrypt3DES进行解密的函数)函数,for循环类似如下:...;)V .line 21 invoke-virtual {v4, p0}, Ljava/io/OutputStreamWriter;->write(Ljava/lang/String...Ljava/lang/String;)V .line 23 invoke-virtual {v4}, Ljava/io/OutputStreamWriter;->flush()V...;->e(Ljava/lang/String;Ljava/lang/String;)I goto :goto_0 .end method 4.在response函数中引用puts方法,就会执行
在日常的Android开发中,日志打印是一项必不可少的操作,我们通过分析打印的日志可以分析程序的运行数据和情况。然而使用日志打印的正确姿势又是怎样呢,如何屏蔽日志信息输出呢,本文将逐一进行回答。...如下,在DroidSettings类中 1 private static final String LOGTAG = "DroidSettings"; 优雅打印日志的姿势 什么才是打印日志的优雅姿势是...onCreate方法体中没有任何关于DroidLog.i方法的调用,但是"sdkVersion=" + Build.VERSION.SDK_INT + "; Locale=" + defaultLocale...v2, "; Locale=" invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava...{v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; return-void .end method 因此,无论是运行时日志屏蔽还是编译期