Android
文章平均质量分 70
Android栏目
不近视的猫
微信公众号:Android猫记
展开
-
如何优雅地使用 when (Switch)
0 -> {}1 -> {}2 -> {}}em…这不是出现了魔术数字了吗?身为有那么一点点追求的程序员👨🏻💻,还得想下,怎么写更合适。这里,我总结了四种方式,并列出相应的场景供大家参考。常量字符串常量数字枚举。...原创 2022-08-19 10:07:58 · 519 阅读 · 0 评论 -
flow 操作符全解析
flow 的执行流程,就生产者和消费者一样,上游产出,下游消费,但是,在默认的情况下,都是生产一个,消费一个,再生产一个,再消费一个,这样进行的。若是生产和消费的速度都很快的话,那倒没有什么问题,但是,若生产速度大于消费速度,就会导致生产效率被强制降低了,因为生产者会一直等到消费者消费完再生产,而这时,我们可以考虑使用 buffer 操作符,可以设置缓存的生成数,就像生产出的商品可以临时存储在仓库一样,并不会阻塞生产者的运行。其实,它算是两个功能的合成,即一个是 buffer 效果,另外一个是合并效果。..原创 2022-08-19 10:07:10 · 721 阅读 · 0 评论 -
我们为什么要用 flow
首先,我们得明确 flow 的适用场景,那便是类似播报机情况,每隔一段时间就播报一段相似的内容。由此,假如我们不使用 flow 的情况下,那我们怎么解决这种问题?List ❎sequence ❎为什么这么快否决它们?因为他们都是阻塞式的,每两个元素间隔的时间,都会阻塞相应的线程,所以就不过多进行说明。而另外两个选项可以实现 flow 的效果,也就是可挂起式运行。回调LiveDataem…回调,也就是观察者模式的代表,确实是可以实现类似的效果,同时,LiveData 也是可以实现相应的效果的。...原创 2022-08-19 10:06:40 · 148 阅读 · 0 评论 -
Flow、SharedFlow、StateFlow 傻傻分不清楚
SharedFlow 就是观察者模式的一个具体实现,可以对观察者进行注册,当被观察者发生改变的时候,就会通知观察者,同时,SharedFlow 还可以存储之前的变化,即当 SharedFlow 变化后,才有观察者注册,这时观察者仍然能够收到之前的变化。其实,这也很容易理解,因为 delay 的时候,该协程都阻塞了,emit 是不会执行到,而当 delay 之后,collect 都执行完成,这时再 emit,自然也不会再执行 collect 里面的代码。关于 Flow 的说明以及使用,可以参考。...原创 2022-08-19 10:03:39 · 1818 阅读 · 3 评论 -
LiveData 与 StateFlow,我该用哪个?
前言LiveData 相信大家都非常熟悉了,但是由于协程与 Flow 的不断发展,之前所使用的技术也正在不断被替代,而 LiveData 的功能与 StateFlow 很相似,所以,很多人都在考虑使用 StateFlow 去替代 LiveData。这里,我们就分析下,LiveData 与 StateFlow 的优缺点,以及我们该如何抉择。LiveData 与 StateFlow 的区别关于 LiveData 与 StateFlow,网上说的最多的区别,其实就是「官方指导文档」中所讲解的这两点,这里我原创 2022-08-05 15:59:12 · 505 阅读 · 0 评论 -
Channel 是什么?
前言Flow 是一种冷流,只有 collect 的时候才会产生数据,而 SharedFlow、StateFlow 虽然是热流,但是,每次 collect 的时候,要么是只能获取最新值,要么把之前存储的值重新都发一遍。有没有一种热流,能更像生产者与消费者,一个专门生产,一个专门消费,答案当然是有的,那便是 Channel。Channel 的使用 GlobalScope.launch { launch { (1..3).forEach原创 2022-08-05 15:58:34 · 414 阅读 · 0 评论 -
channel 进阶
从『Channel 是什么?』中,我们已经清楚 channel 的基本使用以及其参数说明,下面,我们来继续学习它的更深入一点的知识。原创 2022-08-05 15:58:00 · 13468 阅读 · 0 评论 -
BroadcastChannel全解析
对于 channel 而言,更多面向的是一对一的情况,因为一旦receive()后,该数据就被获取了,后续再receive(),也无法拿到之前的数据。但是,类似的,Flow 与 sharedflow 是相对应的,与 channel 相对应的是 BroadcastChannel。...原创 2022-08-05 15:57:11 · 1351 阅读 · 0 评论 -
关于命令模式的误区,你知道了吗
最近项目开发需要用到命令模式,之前没学过,就过去研究了下。但是,理解后发现网上对于命令模式的讲解大多晦涩难懂,并且在选例时容易让人进入一个误区。所以,干脆自己写篇命令模式的讲解,用于自我总结,当然,若能帮上各位同学,那就是赚了。...原创 2022-08-05 15:56:31 · 124 阅读 · 0 评论 -
初始化Library新姿势——App Startup
}println("初始化 ALibrary 成功")}}在这篇文章中,我们尝试使用进行初始化。原创 2022-08-04 10:12:39 · 166 阅读 · 0 评论 -
App Startup原理解析
在上篇文章中「初始化Library新姿势——App Startup」我们学会了的使用,下面我们接着学习的原理。原创 2022-08-04 10:12:03 · 263 阅读 · 0 评论 -
DialogFragment与Dialog有什么区别
在开始学习 Android 的时候,制作对话框,无疑都是直接使用 Dialog,然后对其进行自定义,而后面推出 DialogFragment 后,更多人都开始使用 DialogFragment 了,那么,DialogFragment 与 Dialog 到底有什么区别?首先,我们来分析下 DialogFragment。...原创 2022-08-04 10:11:23 · 1591 阅读 · 0 评论 -
因为 QUERY_ALL_PACKAGES 权限,我们上不了 Google Play 了
em…今天刚上班就被告知要移除权限,做代码兼容,否则上不了 Google Play 了。if (!}i++) {}}}}当然,并不是这个权限没有了,而是被列为敏感权限,必须有充分的理由说明,才允许上架 GP,否则还是被一票否决。其实说白了就是大路已经被封了,留了条小路,但是小路只能看,不能走。详情可以看看官方说明,假如你们的 App 也需要上架 GP 的话。「使用广泛的软件包(应用)可见性 (QUERY_ALL_PACKAGES) 权限」...原创 2022-08-04 10:10:28 · 4901 阅读 · 5 评论 -
Preferences DataStore全解析
DataStore 是用来取代的一种简易数据存储的解决方案。下面我们来看看如何使用。原创 2022-08-04 10:08:41 · 803 阅读 · 0 评论 -
重拾 Kotlin 协程——异常剖析(4)
前言我们通过上一篇文章知道,在 Android 中,假如线程发生了异常,会导致 App 直接退出,那我们来看看,协程发生异常后,现象会怎么样。示例代码: override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) GlobalScope.launch {原创 2022-08-19 10:08:20 · 425 阅读 · 0 评论 -
重拾线程——子线程异常,为什么 App 会崩溃(3)
前言在 JDK 中,若子线程发生异常崩溃,并不会阻碍主线程的运行。fun main(args: Array<String>){ Thread{ throw NullPointerException("空指针异常") }.start() Thread.sleep(1000) println("主线程执行完成")}运行结果:Exception in thread "Thread-0" java.lang.NullPointerExcept原创 2022-05-07 18:53:30 · 1939 阅读 · 1 评论 -
重拾 Kotlin 协程——获取返回值(3)
前言当我们在同步代码块中执行代码时,获取返回值是一件十分轻松的事情,直接运算结果进行返回即可。但是,协程是一种异步的概念,所以需要一些特别的操作才能获取协程的返回值。经研究,一般使用以下三种:asyncsuspendCoroutinesuspendCancellableCoroutineasync相信大家对 async 都十分理解了,主要流程就是使用 async 去开启协程,然后调用 async 返回的 Deferred 的 await() 方法,即可获取 async 协程运算的结果。具体的原创 2022-05-07 15:20:40 · 3818 阅读 · 0 评论 -
重拾线程——FutureTask 是如何吃掉异常(2)
前言首先,我们先写个示例代码来运行 FutureTask: val futureTask = FutureTask { println("futureTask 正在执行") throw Exception("我是测试异常") println("futureTask 发生异常了!") return@FutureTask "1" } Thread(futureTask).start()运行结果:futureTask原创 2022-04-24 19:00:42 · 2521 阅读 · 0 评论 -
重拾线程——异常处理(1)
关于线程的异常,我们可以先看一个小栗子🌰:fun main(args: Array<String>) { println("-------1---主线程开始执行") try{ Thread{ println("-------2---子线程开始执行") throw Exception("error!!!") println("-------3---子线程异常后执行") }.st原创 2022-04-24 17:19:45 · 1877 阅读 · 0 评论 -
重拾 Kotlin 协程——结构化并发(2)
取消协程我们都知道,通过以下代码就可以启动一个协程进行运行: CoroutineScope(Dispatchers.IO).launch { }但是,这个跟我们启动线程一样,具有一个很大的问题,就是不可控性,我们知道它什么时候启动,却不知道什么时候销毁,就像我们跳转在一个页面进行数据加载的时候,可以使用协程去加载,但是,我们也希望当该页面销毁的时候,该协程也能够销毁。其实,协程也提供这样的一种方式:class MainActivity : AppCompatActivity() {原创 2022-04-19 17:23:33 · 1373 阅读 · 0 评论 -
重拾 Kotlin 协程——调度器(1)
基础使用我们若要使用到 Kotlin 协程,首先需要添加依赖:dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'}然后通过以下代码就可以启动协程: CoroutineScope(Dispatchers.Main).launch { }这样,就能够在主线程中执行代码了。调度器而这个调度器不仅只有 Dispatchers.Main原创 2022-04-18 03:13:27 · 656 阅读 · 0 评论 -
自动更改 versionCode
前言在我们每次发布新包的时候,总是需要更改 versionName 和 versionCode,versionName 是展示给用户看的版本名字,所以,每次发布都需要更改,这个可以理解,但是 versionCode 基本都是自增,那有没有什么方式可以让其在发布的时候自增?答案当然是可以的,不然这篇文章就不会发布出去了。正文首先,我们在 gradle.properties 中定义一个 APP_VERSION_CODE :然后在 build.gradle 更改 versionCode 为:ver原创 2022-02-15 16:59:56 · 1746 阅读 · 1 评论 -
sleep()为什么要 try catch
前言当我们在 Java 中使用 sleep() 让线程休眠的时候,总是需要使用 try catch 去包含它: try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }但是,我们却很少在 catch 中执行其它代码,仿佛这个 try catch 是理所当然一样,但其实,存在即合理,不可能无缘无故地多出一个 try原创 2022-02-02 00:32:57 · 2661 阅读 · 0 评论 -
面试官:Java 和 Kotlin 混用会出现什么问题
前言这其实是上年面试时遇到的问题,后续去搜索,都没找到合适的答案,直至在工作中真的写到这 bug 后,才知道,Java 和 Kotlin 的混用,还是真的有坑的,真是血与泪的教训!原由我们都知道,在纯 Java 开发中,很容易出现 NullPointerException,而 Kotlin 的空安全就能很大一个程度避免该问题,也就是在声明类型的时候,就决定好该类型是否能够容纳 null,以此,我们来写个 kotlin 方法:KotlinUtils.kt:fun printMsg(msg : St原创 2022-01-28 17:23:48 · 3513 阅读 · 0 评论 -
同步屏障与异步消息,从入门到放弃
前言在之前的文章中《面试官:如何提高 Message 的优先级》关于如何提高 Message 的优先级提出个人的理解,有大佬在后面评论所提到的同步屏障+异步消息也能提高 Message 的优先级。首先表示感谢,而外也发觉自己对同步屏障的理解还不够,所以,赶紧研究研究。同步屏障与异步消息说明首先,我们得了解下,什么是同步屏障,它跟异步消息又有什么关系?这里的同步和异步又是什么?这里,我们又要涉及到了 Handler 机制。Android 真是博大精深,而且变化贼快,越学越怀疑自己当年是不是入错行了。原创 2021-04-23 16:45:11 · 327 阅读 · 1 评论 -
给Bugly增加自定义处理异常功能
场景说明相信大家目前已上线的项目都有着捕获崩溃的机制,有些可能是自己写的,有些可能是使用第三方的,例如 Bugly。但是,无论使用什么框架,基本上都是围绕着UncaughtExceptionHandler进行,也就是说,只有应用崩溃了才能上报异常信息。嗯?为什么是应用崩溃了才能上报信息?那是因为大部分框架都是使用这种方式进行异常捕获和上报: Thread.setDefaultUncaughtExceptionHandler(object : Thread.UncaughtExcept原创 2021-04-21 23:22:14 · 1052 阅读 · 0 评论 -
面试官:如何提高Message的优先级
面试经历面试官:看你简历上写着看过 Handler 机制源码,说下如何提高Message的优先级?内心分析中:首先,我们先分析下,这个 Message 是由 Handler 进行发送,然后添加到 MessageQueue 中,Looper 遍历 MessageQueue 获取 Message 出来执行。而 MessageQueue 是通过时间对 Message 进行排序的,若想提高 Message 的优先级,那就是要把 Message 排在 MessageQueue 的前面,这样就会优先执行了。原创 2021-04-20 23:34:31 · 401 阅读 · 4 评论 -
动态代理说明以及模拟 Retrofit 实践
什么是动态代理动态代理的核心为代理模式,代理模式在实践的过程分为静态代理和动态代理。关于代理模式的说明,百度百科是这样说的:代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。使用代码的话语去说明,其实就是定义一个接口,后续的对象 A、B 可以实现该接口并实现其抽象方法 method,但是在访问 A、B 的时候,可以不直接引用 A、B 对象,而是通过接口引用直接调用 method原创 2021-04-20 15:38:20 · 106 阅读 · 0 评论 -
写给还不会在项目中使用RxJava的讲解
首先还是强调下,该文如题所示,若已会使用,那可直接略过,返回上一页了。前言或许会有人疑问,都什么年代了,还不会 RxJava?em…还真有,这并不关乎能力,很大原因在于环境。特别是一些公司技术要求会比较保守,或者技术负责人没有使用这种技术,那刚出来工作的同学就自然而然地不懂怎么使用了。由此,对于一些了解 RxJava,却一直不会在项目开发使用的同学,个人希望能够提供一点帮助,让他们能在项目中逐渐使用。毕竟连上手都不懂,更何谈精通。当然,也有人觉得,网上都这么多优秀的 RxJava 的文章了,为什.原创 2021-04-07 02:04:57 · 245 阅读 · 0 评论 -
Android Studio更新4.1后插件不可用
之前有更新过 Android Studio 到 4.1.0,但是…很多插件都不可用了!!!然后就安装回 4.0,一切完美如初。过了很久,看了下推送,Android Studio 已经更新到了 4.1.3,心想,应该没问题了吧?可惜年轻的我,还是被套路,很多插件还是不可用,去查了下,这些插件也没有更新版本,所以,只能卸载之前的插件,安装其它类似功能的插件!。没错,这就是解决办法,再强调下:卸载之前的插件,安装其它类似功能的插件!为了便于大家的对于插件的搜查,我列下我所替换的插件:Butt原创 2021-04-06 15:03:58 · 935 阅读 · 0 评论 -
制作一个永远不会崩溃的App
最近想给 App 加上一个崩溃后自动重启的功能,便去查找了下资料,毕竟有很长一段时间没弄过。不搜不知道,一搜吓一跳,居然看到这库的实现思路,居然能够让 App 产生异常后,不会崩溃。我当场的表情是这样的: 学完后,表情是这样的:好了,废话不多说,赶紧进正文。该库的 GitHub 地址为:https://github.com/android-notes/Cockroach其有两个版本,两个版本的思路是不一样的,但是能够实现同样的功能——App 不会崩溃。在讲解它的原理之前,我们还是来简原创 2021-03-31 01:38:29 · 1655 阅读 · 4 评论 -
自定义Gradle Plugin+字节码插桩
原本是想写一篇介绍字节码插桩的文章,但无奈的是使用字节码插桩之前需要使用到自定义 Gradle Plugin,似乎暗示着这篇文章并不会短。在了解字节码插桩之前,我们先了解编译插桩。编译插桩是什么相信大家都使用过 ButterKnife,了解过它原理的都知道,它是在编译期间生成相应的 java 文件,到运行时,通过反射机制去获取该生成类,并调用其绑定方法,从而做到控件绑定。(什么?你还没了解过 ButterKnife 原理?赶紧去看看吧——《从手写ButterKnife到掌握注解、Annotatio原创 2021-03-30 17:05:46 · 747 阅读 · 0 评论 -
字节码?别怕,我带你分析分析
使用 java 的人很多,使用 kotlin 的也不少,不过,对于它们编译后的文件,也就是 class 文件,却很多人望而却步,一是它晦涩难懂,二是它对于实际上的业务开发的帮助没那么常用。但是,它并不是没有用处的,只是你不懂而已。开始正文。查看 class 文件首先,我们得先写个 Java 文件:public class Test { public void sayHello(){ System.out.println("Hello"); }}然后使用 ja原创 2021-03-28 02:16:07 · 133 阅读 · 0 评论 -
惊了,还有这种方式手写ButterKnife
ButterKnife的应用如题所示,这篇文章主要讲解手把手教学写个简易版 ButterKnife,所以,还是先看看 ButterKnife 怎么使用,不过大多数人都用过,就不详细介绍,若有需要,请参考:https://github.com/JakeWharton/butterknife虽然有人觉得,在 kotlin 中,使用 KTX 工具或者使用 MVVM,已经很少使用 ButterKnife 了,所以觉得没必要去研究 ButterKnife,但是我们学习并非是为了使用,而是为了清楚其原理及构造原创 2021-03-26 11:34:39 · 190 阅读 · 0 评论 -
你真的了解GC吗?
GC是什么?在计算机科学中,垃圾回收(英语:Garbage Collection,缩写为GC)是指一种自动的存储器管理机制。当某个程序占用的一部分内存空间不再被这个程序访问时,这个程序会借助垃圾回收算法向操作系统归还这部分内存空间。垃圾回收器可以减轻程序员的负担,也减少程序中的错误。——来自维基百科通俗来讲就是,你家里有 100 平方,你会买各种生活用品和家居回来,这些物品都会占用空间。过了一段时间,你会通过各种情况去判断这些物品还需不需要,然后再去进行清除和整理。其中:家里100 平方:原创 2021-03-23 16:42:06 · 2777 阅读 · 10 评论 -
来,带你手写个性能检测工具
性能优化,基本每位 Android 开发都需要考虑这个问题。像LeakCanary、hugo这些都是大家常用的性能检测工具,而这次我要讲的是 BlockCanary,由于这个库很久没更新了,所以可能很多人不认识,但是这并不妨碍我们去理解它的实现原理。OK,开始吹水正文功能介绍首先,先祭出GitHub地址https://github.com/markzhai/AndroidPerformanceMonitor该库的功能主要为检测在主线程运行的操作时长,假如运行超过一定时间(默认为1000毫秒)原创 2021-03-18 02:27:45 · 449 阅读 · 1 评论 -
都快面试了,还不赶紧复习下HTTP!
什么是HTTP超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。——来自百度百科说白了,其实就是请求-响应协议。请求部分首先,我们先来看个栗子????:在浏览器的地址栏中输入https://blog.csdn.net/m0_46278918,回车。可以看到其请求数据:这些数据已经被浏览器进行排版过了,其实其主要格式为:GET /m0_4原创 2021-03-17 00:12:16 · 96 阅读 · 1 评论 -
Android App的构建与运行
App的正常构建运行流程Instant Run方式原创 2021-03-14 11:36:54 · 89 阅读 · 0 评论 -
性能优化与内存优化
性能优化主要以这四个方向进行优化:稳定流畅耗损apk 瘦身稳定避免内存溢出异常捕获反馈机制流畅异步执行减少内存抖动耗损减少没必要的网络访问或合并相关网络请求加载合适尺寸的图片而非原图apk瘦身删除没必要的资源文件或依赖包使用 webp 替换 png、jpg等,或对于图片进行适当压缩开启混淆使用 svga、lottie 代替 gif 或帧动画插件化内存优化主要以这五个方向进行优化:内存泄漏图片分辨率图片压缩缓存池内存抖动内存泄漏原创 2021-03-12 16:58:34 · 436 阅读 · 0 评论 -
GC运作原理
GC 分两块功能:内存划分和分配垃圾回收而垃圾回收目前有两种比较常用的算法:引用计数算法根搜索算法以上两种算法只能进行标记哪些能回收,哪些不能回收,而具体回收还使用了其它算法:标记-清除算法复制算法标记-压缩算法分代算法...原创 2021-03-12 16:12:09 · 118 阅读 · 0 评论