- 博客(62)
- 收藏
- 关注

原创 关于coroutine的异常捕获和取消机制
如果我们在launch外面try catch 意图捕获异常的话如果不是在抛出异常的地方直接捕获异常,那么在外面是捕获不到的,会直接导致应用奔溃。
2024-10-15 12:29:37
939

原创 flow 终极系列
collectLatest不会等待下游把事件处理完,而是继续发送,当下游收到新的事件后,会中止前面一个事件的处理,所以,我们只有看到,最后一个事件被处理完成,其他的都是知识开始,就中止了。普通的flow没有一个缓冲区,所以只能等前面的数据处理完之后,再发送下一个,但是如果我们给他加一个缓冲区buffer,这样,上游数据的发送不受下游处理速度的影响。会确保处理顺序,只有当前的流全部处理完毕后,才会继续处理下一个流,这点和。上游又发送了5,处理后变成6发送出去了,前一个的1变成3刚完成,发送了3。
2024-10-10 08:00:00
2763
原创 fragment 异常 InstantiationException
BadgeListInfoDialog有了有参数的构造函数,就没有了默认的无参构造函数。接手的项目过了下firebase和内存泄漏,还是有很多常见共性的问题。如果自定义了带参数的构造函数,系统无法找到无参构造方法,直接崩溃。这个异常也是非常常见,但是很多人不会去修复的。传递参数是 Android 的官方推荐做法。所以比如页面销毁重建的时候,就会报这个异常。在oncreate中。
2025-04-19 17:07:24
167
原创 关于viewpager常见的泄漏
但是这样比如在 mainfragment就就强引用了子fragment,这种强应用leakcanary不会报异常,但是Android studio的profile会报泄漏。在一个页面中 如果有用到tab,有需要进行fragment的切换,经常就看到了。这样就可以不直接引用fragment。
2025-04-19 16:29:40
220
原创 根据Exif信息纠正图片方向
throw IOException("无法解码图片: $originalPath")// 保存旋转后的图片,并重置 Exif 方向为正常。else -> 0f // 无需旋转。// 如果方向正常,直接返回原图路径。// 创建临时文件保存旋转后的图片。/ 工具函数:纠正图片方向并保存到新文件。// 读取原图的 Exif 方向。// 回收 Bitmap 内存。
2025-04-19 16:15:00
266
原创 上传文件worker
大文件在上传时如果全部加载进内存,容易造成 OOM(Out of Memory)。:网络中断时,如果是整个文件上传,一旦失败就要重头再来,耗时耗流量。:可以做断点续传、上传进度监控、更好地用户体验。如果文件很大,大到一个什么范围需要分段上传呢?:需要视设备内存情况和网络稳定性决定。:推荐强烈使用分段上传。:直接上传通常没问题。
2025-04-12 18:19:42
149
原创 通过uri获取文件路径手机适配
其实有的手机通过选择图片或者文件后返回的uri并不一定是媒体uri,也可能是document uri,造成这个时候直接通过 uri查询,找不到_data字段,需要将 document uri中分离出类型和id,在拼凑成新的uri,在通过contentprovider查询,才可以查出 _data字段中真正的路径。但是根据文档其实Android 10 之后是有新的字段,但是手机厂商众多,实现方式不一,还是找不到path怎么办,官方是说可以从 RELATIVE_PATH获取路径。
2025-04-12 17:39:01
449
原创 关于遗留项目重构反复看
如果一定要集成一个基类,比如实在不想每个fragment都添加方法,可以讲这个base写成具体的功能,不过Philip还是很拒绝使用继承来实现这些~~~~2. 关于一些可能的公共功能,将功能从viewmodel中抽离出来,并且用interface的方式来引用,通过依赖注入来初始化,便于测试。可能不太有必要,一些公用的方法可以通过ext扩展函数来实现。1. 关于 base fragment 的必要性?3.有些很好的flow的方式,可惜没有源码贴不出来。这个关于遗留项目的重构视频可以反复看。
2025-03-30 11:07:22
317
原创 关于application的persistent属性
从 Android 5.0(API 21)开始,Google 已不再允许普通应用使用 android:persistent="true",这个标志 仅适用于系统级应用(如 SystemUI、Telephony)。该属性用于指定 应用是否应该在系统启动时持久运行。如果设置为 true,Android 会尝试在设备启动时保留该应用,并尽可能不杀死它,即使系统内存紧张。作为系统应用,如果有persistent属性,则有可能无法重装,卸载等。之前的应用用了这个属性,且正好又是系统APP,
2025-03-29 14:15:10
210
原创 AlarmManager添加定时任务
通过AlarmManager添加定时任务,即使应用被杀死了,也会启动intent。用户静默安装前,定时自启动自身应用。直到应用启动完成,取消其他的定时任务。
2025-03-16 19:37:16
229
原创 Android studio取消代理
所以当取消代理的时候,只是将设置中的代理取消勾选,可视同步代码的时候,一直报org.apache.http.conn.HttpHostConnectException: Connect to 127.0.0.1:7890。Windows :C:\Users\Administrator.gradle下的gradle.properties中。Mac :/Users/.{用户目录}/.gradle下的gradle.properties中。以下为不同客户端下gradle.properties文件所在的目录。
2025-02-25 15:27:50
294
原创 旧项目内存泄漏修复
有个旧项目内存泄漏问题,用的是viewpager,页面多次跳转后,内存明显一直在增长,最后发现是viewpager中对fragment的引用导致。所以需要对adapter进行改造,不直接引用fragment,而是fragment的class。改造之后,页面跳转内存就平稳了。
2025-01-09 10:26:21
194
原创 采用koin 依赖注入进行viewmodel单元测试
桌面开发的viewmodel 和Android的viewmodel 创建方式不一样,Android有屏幕旋转,生命周期等感知。这样就可以通过注入的方式初始化viewmode。测试class要继承 KoinTest。在测试开始时,对koin进行初始化。
2024-11-12 19:04:11
605
原创 compose 桌面开发中如何使用KOIN依赖注入
在composable中使用viewmodel。在main.kt中初始化koin。写法和Android略有不同。其中module定义。
2024-11-11 17:55:28
288
原创 在多模块应用中使用navigation不知不觉都是这么用
核心common模块定义了Route1->screen1,Route2->screen2,Route3->screen3.....如果我现在单独使用 featureB,但是featureB中因为导航的这个逻辑,又要不得不去关联featureA。假设我们有主模块 app, 功能模块 featureA, featureB,所以,我们不该在内部的功能部分看到navigate的导航逻辑。所以,需要把导航的逻辑到需要通过lambda来提升到外部去。我们把导航逻辑写到模块中带来的问题是,
2024-11-01 09:12:19
165
原创 compose.material3 中的DatePicker在 desktop 平台同样可以适用
【代码】compose.material3 中的DatePicker在 desktop 平台同样可以适用。
2024-10-30 14:11:07
266
原创 compose navigation 自定义navtype
navController.navigate 直接放入带自定义参数的 route,在接收端,通过 toRoute直接获取组装后的带自定义参数的route,但是前提条件是,需要注册号typeMap。可以看到 DogDetailRoute带了两个参数,一个是自定义类型Dog。大部分情况下,我们应该是传狗的ID,然后在狗详情界面,通过查询本地数据库or API,去获取狗详情信息。通过自定义navtype可以方便的在导航过程中,传递自定义参数。即两个页面,一个狗列表页面,点击列表项,进入狗详情界面。
2024-10-19 22:14:18
324
原创 关于Android12以上的闪屏兼容
theme.xml</style></style>31多了动画定义<target其中 logo 定义图标,logo_animator定义动画了对logo中 animationgroup进行一些动画操作logo.xml<group</group></vector>应用主题这样当应用启动后,不需要添加额外的界面,就可以有一个logo的动画闪屏但是动画结束,如果我们想延长呢可以加setKeepOnScreenCondition) {!
2024-10-16 12:18:42
566
原创 微信消息语音播报秒实现
注册一个监听系统消息的服务实现这个服务,解析消息通知,如果是来自微信,则组装成微信消息,提取发送者,和消息内容,更新到livedata中怎么启动这个消息监听服务呢这时候会启动系统设置界面,我们需要允许我们的应用如何判断系统是否允许我们监听了呢允许了则直接跳过,不允许的话,启动设置界面,引导用户设置。
2024-10-16 11:04:30
838
原创 Room 引用复杂数据
在使用room的时候,如果要保存的entity中有 bitmap,或者其他复杂的对象,我们没办法直接保存,这个时候,就涉及到类型转换。比如下面这个entity,想要直接保存bitmap,这个时候,我们需要告诉room如何进行类型转换。写一个Converters,具体的转换方法上添加@TypeConverter注释。这样在保存数据的时候就可以直接操作了。然后将这个注册到数据库。读取也是可以直接返回。
2024-10-15 11:25:47
189
原创 关于Android的存储
关于数据的存储sp,datastore,内部存储,外部存储,数据库等对比,大概的一些概念关于内部存储和外部存储的一些区别,以及API29与API30平台上的区别PL这个视频大概有说到内部存储只有自己的应用可以访问,而且应用卸载后,可一起删除外部存储的的话,有个问题,就是应用卸载之后,文件还遗留着,然后Android就出了storage scope来解决这个问题,但是这个在Android 10之后引入的storagescope,但是在Andorid 11之后才强制;
2024-10-14 18:34:14
399
原创 datastore读取方式
看到在datastore上存储自定义的可序列化的对象之前项目中用到过datastore的preference,当时官网的介绍是这样的。
2024-10-14 18:06:43
357
原创 DataStore存储数据+加上加密
定义data class,添加 @Serializable 标签= null,= null这里先展示没有加密的的序列化存储的时候,将实例值转换成json string,再转换成bytearray写出到输出流,就可以保存到datastore的文件上了读取的时候,从输入流中读取转成json string, 再通过json解析成 UserSetting实例//继承datastore的Serializer,类型是我们定义的UserSettings//将输入端的内容先转换成string。
2024-10-13 18:50:13
981
原创 Android上的AES加密
虽然这个视频讲的非常详细,但是涉及到具体底层算法,大致流程1. 将数据转成HEX或者byte array2.将数据分层一块块等大小的数据3.将数据和key 进行一次混合,加密之后的输出,在生成新的key4.将新的key和下一个数据,进行加密计算,继续重复生成的KEY长度有128,192,256,不同的的长度对算法的速度有影响当然key的长度越长,可能越安全这样具体的算法是什么呢。
2024-10-13 12:12:26
853
原创 调用AI 通过相机识别地标
我们希望可以通过ts模型识别图片,这个结果我们放在 Classification 中,自己定义。定义一个识别接口,然后我们可以有TS模型识别,以后有其他的模型,也可以实现其他的模型进行切换。并不是每一帧都是分析,所以加了 frameSkipCounter‘处理图片,根据ts 的文档,把图片裁剪处理成321*321。实现通过ts的API处理bitmap,识别,读取结果。我们在相机的Analyzer中使用分析器。如何在Android上使用ts模型。每60帧才分析,提高性能体验,这个模型大概就有50M了。
2024-10-11 12:37:02
1034
原创 CoroutineWorker 压缩图片示例
它允许开发者在后台执行任务,比如数据同步、图片上传、定期执行任务等,而不需要担心任务被中断,即使应用关闭或重启,任务仍会在条件满足时继续执行。根据图片,因为不知道图片多大,还一次次的压缩,直到达到压缩的指标大小了,将文件写入文件。可以设置任务的执行条件,比如仅在设备充电、联网等条件满足时执行。提供了更自然和可读的异步编程模型,避免了复杂的回调嵌套问题。会确保这些条件符合时,任务才会被执行。:通过使用 Kotlin 协程,:与普通的后台线程不同,怎么启动这个woker呢。
2024-10-10 20:08:09
401
原创 stateflow一些数据依赖关系的使用
如果我们分开存储,像刚开始被注释掉的那些代码,用一个单独的localuser来存储本地用户,当用户列表变化的时候,需要监测是不是local,如果是local,要更新localuser,其中 chatpreview中的最新消息,是把所有消息,根据当前用户的过滤后,再找出最近的时间的那条,再取message。当用户信息变化的时候,需要监测下,当前是不是localuser,如果是,则localuser又要更新一下。上面,本地用户其实是用户列表中的一个特殊用户,他的ID是local。
2024-10-09 10:04:47
464
原创 stateflow vs composestate
2.另外如果要存储color值,就是activity销毁后还可以恢复的话,stateflow操作会简单点。在viewmodel中定义两个颜色,一个用stateflow,一个用compose的 state。1.但是如果想要compose free 的话,还是推荐 stateflow。3. stateflow,还有一些statein map 操作等。来随机生成一个颜色,并给上面的两个变量赋值。使用起来都没什么问题的。
2024-10-09 08:30:00
236
原创 livedata,stateflow,sharedflow,flow啥时候使用
flow是普通的流,是冷流,所以只有当订阅的时候,才开始发送事件,所以当触发triggerFlow的时候我们可以看到数据的发送过程,从0~4,监听到数据变化了,更新textview,当界面切换后,又回到原始的。Shareflow 和stateflow一样,属于热流,但是Shareflow不会存值,所以横竖屏切换后,之前的值不在了,不会引发事件和更改。所以更适合做消息弹窗。livedata 和 stateflow比较像,可以hold value,所以初始化的时候,都有传入默认的值。
2024-10-08 14:49:11
520
原创 有点晕,inline, crossinline,noinline小计
我们启动了一个协程,但是在normalForeach的lambda中无法使用delay,因为这里其实是一个函数对象,会指向到另外一个函数方法,没有协程的上下文环境,但是内敛函数就不一样了,他相当于是把lambda中的内容拷贝平铺过来了,所以,在inlinedForeach中可以使用协程的上下文环境,delay可以执行。另外,当把一个函数声明为inline的时候,他的lambda参数也是inline的,所以无法通过函数地址引用的方式来调用。内敛函数,因为相当于被拷贝过来了,可以直接返回到main,
2024-10-08 12:24:36
418
原创 coroutine 陷阱
我们启动 createFile 任务,任务向文件写入10万行的数据,需要耗费比较多的时间,然后50毫秒后,我们取消了测试任务,因为有writeline中有 ensureActive,即任务被取消的时候,会抛出cancellation异常,那么writeline因异常终止,然后到了finally,正常来说,finally中的 deletefile应该执行,但是deletefile在同一个launch scope,所以delete中的任务,也没有执行。当界面离开,无论代码运行到delay,还是client。
2024-10-07 15:30:26
723
原创 冷流还是热流
可以看到网络监听注册了两次,所以对冷流的数据收集是独立的。这不是我们想要的,我们希望只监听一次,然后只关心最新的数据,这个数据可以多个观察者共享,这时候,就希望把冷流变成热流,shareIn。shareIn 和 stateIn区别在于是否缓存最新的值,后续还有区分的视频,如果是事件类型用shareflow像消息提示,snackbar,原因是,冷流是只有有订阅者后,才开始发送数据。所以需要collect之后,才有数据。像之前的例子也有说到callbackflow,他也是一个冷流,之前有个例子,监听网络状态。
2024-10-05 22:17:21
372
原创 如何在compose中正确的collect数据
两者的区别,是否感知生命周期,如果希望在界面不可见的时候停止订阅,比如跳转,比如进入后台则使用collectAsStateWithLifecycle,collectAsState则不会停止。将冷流转换成热流stateflow的场景,基本上是我们需要费好大力气才获取的值,然后也可能有多个订阅者,我们想把值缓存起来,不用多次去请求,发送,这时候,就进行stateIn转换。另外一个SharingStarted.WhileSubscribed 有两个参数,一个是 停止 的时间,另外一个是值缓存的时间,默认是永久。
2024-10-05 14:53:56
361
原创 flow,channelflow,callbackflow初体验
API文档里面还有说到 flow 中的emit只能严格的在block所在的dispatcher中执行,来维持flow的上下文,即我们不能再flow中切换dispatcher。trySendBlocking方法尝试发送数据到Channel中,如果发送成功则返回true,如果Channel已满则会阻塞当前协程,直到Channel有可用空间为止。trySend方法尝试发送数据到Channel中,如果发送成功则返回true,如果Channel已满则立即返回false,而不会阻塞。
2024-10-05 10:38:12
580
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人