自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

不近视的猫的博客

微信公众号:Android猫记

  • 博客(87)
  • 资源 (3)
  • 收藏
  • 关注

原创 制作一个永远不会崩溃的App

最近想给 App 加上一个崩溃后自动重启的功能,便去查找了下资料,毕竟有很长一段时间没弄过。不搜不知道,一搜吓一跳,居然看到这库的实现思路,居然能够让 App 产生异常后,不会崩溃。我当场的表情是这样的: 学完后,表情是这样的:好了,废话不多说,赶紧进正文。该库的 GitHub 地址为:https://github.com/android-notes/Cockroach其有两个版本,两个版本的思路是不一样的,但是能够实现同样的功能——App 不会崩溃。在讲解它的原理之前,我们还是来简

2021-03-31 01:38:29 1644 4

原创 自定义Gradle Plugin+字节码插桩

原本是想写一篇介绍字节码插桩的文章,但无奈的是使用字节码插桩之前需要使用到自定义 Gradle Plugin,似乎暗示着这篇文章并不会短。在了解字节码插桩之前,我们先了解编译插桩。编译插桩是什么相信大家都使用过 ButterKnife,了解过它原理的都知道,它是在编译期间生成相应的 java 文件,到运行时,通过反射机制去获取该生成类,并调用其绑定方法,从而做到控件绑定。(什么?你还没了解过 ButterKnife 原理?赶紧去看看吧——《从手写ButterKnife到掌握注解、Annotatio

2021-03-30 17:05:46 672

原创 一大波表情包来袭,还不赶紧收藏下!!!

看过我前几篇博文的应该知道,现在我转变了下写作风格,希望把技术文写的简单易懂,大家能够在轻松的环境下阅读完,这时,表情包变得不可或缺了。免得每次都需要上传,干脆拿一篇文章纯粹存储表情包,方便后续博文书写,同时有需要的同学可自行 Copy。废话不多说。表情包持续更新!!!喝茅台<img src="https://img-blog.csdnimg.cn/20210326220150376.jpg" width = "150" >开心<img src="https://im

2021-03-26 22:05:42 2698 1

原创 惊了,还有这种方式手写ButterKnife

ButterKnife的应用如题所示,这篇文章主要讲解手把手教学写个简易版 ButterKnife,所以,还是先看看 ButterKnife 怎么使用,不过大多数人都用过,就不详细介绍,若有需要,请参考:https://github.com/JakeWharton/butterknife虽然有人觉得,在 kotlin 中,使用 KTX 工具或者使用 MVVM,已经很少使用 ButterKnife 了,所以觉得没必要去研究 ButterKnife,但是我们学习并非是为了使用,而是为了清楚其原理及构造

2021-03-26 11:34:39 187

原创 来,带你手写个性能检测工具

性能优化,基本每位 Android 开发都需要考虑这个问题。像LeakCanary、hugo这些都是大家常用的性能检测工具,而这次我要讲的是 BlockCanary,由于这个库很久没更新了,所以可能很多人不认识,但是这并不妨碍我们去理解它的实现原理。OK,开始吹水正文功能介绍首先,先祭出GitHub地址https://github.com/markzhai/AndroidPerformanceMonitor该库的功能主要为检测在主线程运行的操作时长,假如运行超过一定时间(默认为1000毫秒)

2021-03-18 02:27:45 442 1

原创 重拾 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 377

原创 如何优雅地使用 when (Switch)

0 -> {}1 -> {}2 -> {}}em…这不是出现了魔术数字了吗?身为有那么一点点追求的程序员👨🏻‍💻,还得想下,怎么写更合适。这里,我总结了四种方式,并列出相应的场景供大家参考。常量字符串常量数字枚举。...

2022-08-19 10:07:58 500

原创 flow 操作符全解析

flow 的执行流程,就生产者和消费者一样,上游产出,下游消费,但是,在默认的情况下,都是生产一个,消费一个,再生产一个,再消费一个,这样进行的。若是生产和消费的速度都很快的话,那倒没有什么问题,但是,若生产速度大于消费速度,就会导致生产效率被强制降低了,因为生产者会一直等到消费者消费完再生产,而这时,我们可以考虑使用 buffer 操作符,可以设置缓存的生成数,就像生产出的商品可以临时存储在仓库一样,并不会阻塞生产者的运行。其实,它算是两个功能的合成,即一个是 buffer 效果,另外一个是合并效果。..

2022-08-19 10:07:10 702

原创 我们为什么要用 flow

首先,我们得明确 flow 的适用场景,那便是类似播报机情况,每隔一段时间就播报一段相似的内容。由此,假如我们不使用 flow 的情况下,那我们怎么解决这种问题?List ❎sequence ❎为什么这么快否决它们?因为他们都是阻塞式的,每两个元素间隔的时间,都会阻塞相应的线程,所以就不过多进行说明。而另外两个选项可以实现 flow 的效果,也就是可挂起式运行。回调LiveDataem…回调,也就是观察者模式的代表,确实是可以实现类似的效果,同时,LiveData 也是可以实现相应的效果的。...

2022-08-19 10:06:40 141

原创 Flow、SharedFlow、StateFlow 傻傻分不清楚

SharedFlow 就是观察者模式的一个具体实现,可以对观察者进行注册,当被观察者发生改变的时候,就会通知观察者,同时,SharedFlow 还可以存储之前的变化,即当 SharedFlow 变化后,才有观察者注册,这时观察者仍然能够收到之前的变化。其实,这也很容易理解,因为 delay 的时候,该协程都阻塞了,emit 是不会执行到,而当 delay 之后,collect 都执行完成,这时再 emit,自然也不会再执行 collect 里面的代码。关于 Flow 的说明以及使用,可以参考。...

2022-08-19 10:03:39 1700 3

原创 LiveData 与 StateFlow,我该用哪个?

前言LiveData 相信大家都非常熟悉了,但是由于协程与 Flow 的不断发展,之前所使用的技术也正在不断被替代,而 LiveData 的功能与 StateFlow 很相似,所以,很多人都在考虑使用 StateFlow 去替代 LiveData。这里,我们就分析下,LiveData 与 StateFlow 的优缺点,以及我们该如何抉择。LiveData 与 StateFlow 的区别关于 LiveData 与 StateFlow,网上说的最多的区别,其实就是「官方指导文档」中所讲解的这两点,这里我

2022-08-05 15:59:12 458

原创 Channel 是什么?

前言Flow 是一种冷流,只有 collect 的时候才会产生数据,而 SharedFlow、StateFlow 虽然是热流,但是,每次 collect 的时候,要么是只能获取最新值,要么把之前存储的值重新都发一遍。有没有一种热流,能更像生产者与消费者,一个专门生产,一个专门消费,答案当然是有的,那便是 Channel。Channel 的使用 GlobalScope.launch { launch { (1..3).forEach

2022-08-05 15:58:34 407

原创 channel 进阶

从『Channel 是什么?』中,我们已经清楚 channel 的基本使用以及其参数说明,下面,我们来继续学习它的更深入一点的知识。

2022-08-05 15:58:00 12354

原创 BroadcastChannel全解析

对于 channel 而言,更多面向的是一对一的情况,因为一旦receive()后,该数据就被获取了,后续再receive(),也无法拿到之前的数据。但是,类似的,Flow 与 sharedflow 是相对应的,与 channel 相对应的是 BroadcastChannel。...

2022-08-05 15:57:11 1328

原创 关于命令模式的误区,你知道了吗

最近项目开发需要用到命令模式,之前没学过,就过去研究了下。但是,理解后发现网上对于命令模式的讲解大多晦涩难懂,并且在选例时容易让人进入一个误区。所以,干脆自己写篇命令模式的讲解,用于自我总结,当然,若能帮上各位同学,那就是赚了。...

2022-08-05 15:56:31 117

原创 如何优雅地画一张图

在 Flutter 中,若我们需要自定义画一张图,则需要用到,不过并不是本篇文章的重点,所以我就直接贴出的相关代码,保证能够正常绘制即可。}}@override}@override}}绘制的效果:其中,最核心的绘制在MyPainter的中。...

2022-08-05 15:55:44 121

原创 手绘板的制作——手绘(1)

通过上一篇文章「如何优雅地画一张图」手绘橡皮擦撤销重制重置图片导出命令模式等功能。具体等到时候想到什么再写什么。

2022-08-05 15:55:21 177

原创 手绘板的制作——重置与橡皮擦(2)

在上一篇文章「手绘板的制作——手绘(1) 」中,我们完成了手绘的功能,这一篇我们在其基础上来讲讲重置与橡皮擦的功能实现。在讲具体的功能实现前,我们需要先弄几个文本,用于笔刷、重置、橡皮擦的功能切换,同时把手绘板的功能抽取出来,放到类中,大致代码如下,由于大多都是 UI 代码,可以直接初略看看即可,若需要自己实践再进行 copy。}@override}// ...

2022-08-05 15:54:22 374

原创 手绘板的制作——命令模式与撤销、重制(3)

我们这篇来了解下撤销、重制的功能,其实也就是 undo 和 redo,在这里我们使用命令模式去设计,若对该模式不了解的话,可以考虑看下「关于命令模式的误区,你知道了吗」。其实对于命令模式,我最开始的理解为命令模式只是为了方便数据的管理和记录,不应该和具体的事务或状态进行绑定,后面经过跟同事的“友好”沟通后,感觉命令模式更符合数据的管理+具体事务执行,这个这样才算是一个命令的独立执行过程,而并非只是对数据进行管理,后续的操作还得自己额外去执行。好了,正文开始。...

2022-08-04 10:15:16 292

原创 手绘板的制作——画布缩放(4)

在这一篇中,我们讲解下画布的缩放,也就是做一个根据手势缩放进行画布缩放的功能。监听手势,当为一根手指的时候,就延续之前的操作,执行手绘操作,当操作为两根手指的时候,则执行缩放功能。对画布进行缩放好了,正文开始!...

2022-08-04 10:14:27 799

原创 手绘板的制作——画布移动(5)

在上文「手绘板的制作——画布缩放(4)」中,我们学会了画布的缩放,这节我们学习下画布的移动,毕竟放大的画布不能移动的话,那放大还有什么意义。=_=

2022-08-04 10:13:59 351

原创 手绘板的制作——画布保存(6)

经过之前的一系列文章的学习,相信大家对于如何制作手绘板已经有了初步了了解,这一篇作为阶段性的一篇,也就是将画布作为图片进行保存。后续想到其它新功能再进行添加。

2022-08-04 10:13:20 260

原创 初始化Library新姿势——App Startup

}println("初始化 ALibrary 成功")}}在这篇文章中,我们尝试使用进行初始化。

2022-08-04 10:12:39 155

原创 App Startup原理解析

在上篇文章中「初始化Library新姿势——App Startup」我们学会了的使用,下面我们接着学习的原理。

2022-08-04 10:12:03 254

原创 DialogFragment与Dialog有什么区别

在开始学习 Android 的时候,制作对话框,无疑都是直接使用 Dialog,然后对其进行自定义,而后面推出 DialogFragment 后,更多人都开始使用 DialogFragment 了,那么,DialogFragment 与 Dialog 到底有什么区别?首先,我们来分析下 DialogFragment。...

2022-08-04 10:11:23 1532

原创 因为 QUERY_ALL_PACKAGES 权限,我们上不了 Google Play 了

em…今天刚上班就被告知要移除权限,做代码兼容,否则上不了 Google Play 了。if (!}i++) {}}}}当然,并不是这个权限没有了,而是被列为敏感权限,必须有充分的理由说明,才允许上架 GP,否则还是被一票否决。其实说白了就是大路已经被封了,留了条小路,但是小路只能看,不能走。详情可以看看官方说明,假如你们的 App 也需要上架 GP 的话。「使用广泛的软件包(应用)可见性 (QUERY_ALL_PACKAGES) 权限」...

2022-08-04 10:10:28 4800 5

原创 都到 2022 了,还想着换行

回首一望,今年已经过了一半,再看看自己的年龄,已经快 30 了,当年对于技术的一腔热血已经洒在了地上。对于现在而言,生活的目标主要不再是追求技术,而是活下去,在一线城市活下去。有可能有人会说,这是在贩卖焦虑,但是对于事实而言,看看一线城市的房价以及自己的薪资,好好算算啥时候能够在一线城市买房,然后再看看今年的互联网裁员潮,这真的只是贩卖焦虑而已吗?...

2022-08-04 10:09:28 71 1

原创 Preferences DataStore全解析

DataStore 是用来取代的一种简易数据存储的解决方案。下面我们来看看如何使用。

2022-08-04 10:08:41 770

原创 重拾线程——子线程异常,为什么 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 1896 1

原创 重拾 Kotlin 协程——获取返回值(3)

前言当我们在同步代码块中执行代码时,获取返回值是一件十分轻松的事情,直接运算结果进行返回即可。但是,协程是一种异步的概念,所以需要一些特别的操作才能获取协程的返回值。经研究,一般使用以下三种:asyncsuspendCoroutinesuspendCancellableCoroutineasync相信大家对 async 都十分理解了,主要流程就是使用 async 去开启协程,然后调用 async 返回的 Deferred 的 await() 方法,即可获取 async 协程运算的结果。具体的

2022-05-07 15:20:40 3741

原创 关于 import 的一些思考

前言当我们使用 Java 或者 Kotlin 开发 Android 的时候,若需要导包,都是直接导入绝对路径的,例如:import android.view.ViewGroup.MarginLayoutParams;但是使用 Dart 开发 Flutter 的时候,却有点不太一样,会提示让你选择绝对路径还是相对路径,例如:那么,问题来了,我们该选哪一种???当然,首先我们先明确一个问题,无论使用哪种导入方式,都不会对 App 的功能造成影响,只是写法的不同而已。dart.dev 建议da

2022-05-07 08:57:34 1209

原创 重拾线程——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 2508

原创 重拾线程——异常处理(1)

关于线程的异常,我们可以先看一个小栗子🌰:fun main(args: Array<String>) { println("-------1---主线程开始执行") try{ Thread{ println("-------2---子线程开始执行") throw Exception("error!!!") println("-------3---子线程异常后执行") }.st

2022-04-24 17:19:45 1866

原创 重拾 Kotlin 协程——结构化并发(2)

取消协程我们都知道,通过以下代码就可以启动一个协程进行运行: CoroutineScope(Dispatchers.IO).launch { }但是,这个跟我们启动线程一样,具有一个很大的问题,就是不可控性,我们知道它什么时候启动,却不知道什么时候销毁,就像我们跳转在一个页面进行数据加载的时候,可以使用协程去加载,但是,我们也希望当该页面销毁的时候,该协程也能够销毁。其实,协程也提供这样的一种方式:class MainActivity : AppCompatActivity() {

2022-04-19 17:23:33 1353

原创 重拾 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 632

原创 自动更改 versionCode

前言在我们每次发布新包的时候,总是需要更改 versionName 和 versionCode,versionName 是展示给用户看的版本名字,所以,每次发布都需要更改,这个可以理解,但是 versionCode 基本都是自增,那有没有什么方式可以让其在发布的时候自增?答案当然是可以的,不然这篇文章就不会发布出去了。正文首先,我们在 gradle.properties 中定义一个 APP_VERSION_CODE :然后在 build.gradle 更改 versionCode 为:ver

2022-02-15 16:59:56 1726 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 2594

原创 面试官:Java 和 Kotlin 混用会出现什么问题

前言这其实是上年面试时遇到的问题,后续去搜索,都没找到合适的答案,直至在工作中真的写到这 bug 后,才知道,Java 和 Kotlin 的混用,还是真的有坑的,真是血与泪的教训!原由我们都知道,在纯 Java 开发中,很容易出现 NullPointerException,而 Kotlin 的空安全就能很大一个程度避免该问题,也就是在声明类型的时候,就决定好该类型是否能够容纳 null,以此,我们来写个 kotlin 方法:KotlinUtils.kt:fun printMsg(msg : St

2022-01-28 17:23:48 3468

原创 为什么你刚入职,我就劝你考虑离职

前言金三银四刚过去,估计不少同学都找到了满意的工作。但是在这个时候,不应该松懈,而是要好好考虑离职的问题。刚经过求职阶段的我们都知道,在求职过程中,有两份东西异常重要:简历:可以理解为工作报告,记录着你在所经历过的项目和所用的知识点。技术能力:面试时重点考核,但是考核的出发点基本都是围绕着你所做过的项目。总结以上两点,其核心为:项目技术点。技术点学习所以,我们在入职一个公司后,需要尽快熟悉里面的项目,梳理其运行流程以及使用了什么技术点。若可以,将这些技术的难点记录下来,并且突破它,毕竟这些

2021-05-11 12:40:11 211 10

原创 Dart单线程理解(与Java完全不同)

Dart 单线程说明在 Java 中,默认为单线程执行,也就是通过main()方法进行执行,按照顺序执行方式运行代码。而 Dart 的单线程跟 Java 的完全不同,虽然都是单线程,但是 Dart 分为三个形式:主线程微任务队列事件任务队列主线程跟 Java 一样,具有唯一性,也就是从main()开始的线程。微任务队列里面包含众多微任务,主要是通过scheduleMicrotask进行调度。事件任务队列里面包含众多事件任务,例如:I/O 事件任务、Timer 事件任务等。Dart

2021-04-24 19:10:36 949

主流游戏搬砖思路及流程.zip

主流游戏搬砖思路及流程,提供各种思路给大家

2021-07-17

雷神_模拟器操作模块 v1.0.1.0.rar

易语言开始操作模拟器用到的雷神_模拟器操作模块 v1.0.1.0

2021-07-17

OKR工作法.zip

O表示目标(Objective),KR表示关键结果(Key Results),目标就是指你想做什么事情,关键结果就是指如何确认你做到了那件事

2020-05-05

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除