本篇文章是我研究的项目整理的一些知识点,方便自查,后续会不断整理旧的内容和添加新的内容,本篇文章也加了一些常用库的地址,方便查找

下划线(“_”)作为数字分隔符

为了方便阅读,数字位数较多的时候,最好使用下划线(“_”)作为数字分隔符

1000000可以用1_000_000表示,1_000_000能够更好的阅读

注意:这只是提高可读性,但这不是必须的,也不影响代码的功能

RecyclerView使用ListAdapter

RecyclerView在频繁的增删改查操作时建议使用ListAdapter

ListAdapter是RecyclerView.Adapter的子类

相比较RecyclerView.Adapter来说,ListAdapter提供了以下优点:

  • 自动计算列表项的差异,从而更高效地更新列表
  • 内置数据集合,可以更方便地对列表数据进行操作
  • 支持异步数据加载和自动更新列表

总之,如果需要对列表数据进行频繁的增删改查操作,使用ListAdapter会更加方便和高效。

LinearLayout动画

android:animateLayoutChanges="true"xml中加个这个属性可以打开LinearLayout自带的动画

ScaleGestureDetector的缩放抖动问题

onScale(detector: ScaleGestureDetector)方法中,return false

detector会在之前的缩放上继续进行计算,就可以避免抖动

class ScaleListener: ScaleGestureDetector.SimpleOnScaleGestureListener() {

private var scaleFactor = 1.0f // 初始缩放比例为 1.0

    /**
     * 缩放进行中,返回值表示是否下次缩放需要重置,
     * 如果返回ture,那么detector就会重置缩放事件,如果返回false,detector会在之前的缩放上继续进行计算
     */
    override fun onScale(detector: ScaleGestureDetector): Boolean {
        scaleFactor *= detector.scaleFactor
        scaleFactor = max(0.5f, min(scaleFactor, 2f)) // 设置最大和最小缩放比例

        this@BaseLayout.scaleY = scaleFactor
        this@BaseLayout.scaleX = scaleFactor
        
        //return true的话,缩放会出现抖动
        return false
    }

    /**
     * 缩放开始,返回值表示是否受理后续的缩放事件
     */
    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
        return true
    }

    override fun onScaleEnd(detector: ScaleGestureDetector) {
    }

}

Android两根和单根手指旋转

两根手指旋转

旋转检测库

Android一些项目知识点整理_android

单根手指旋转

private var degree = 0f
private var oriX = 0f
private var oriY = 0f

//注意这里取的都是event.x不是event.rawX
    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                oriX = event.x
                oriY = event.y
                degree = rotation
            }
            MotionEvent.ACTION_MOVE -> {
                val tempRawX = event.x
                val tempRawY = event.y
                val first = Point(oriX.toInt(), oriY.toInt())
                val second = Point(tempRawX.toInt(), tempRawY.toInt())
                val cen = Point( width/2, height/2)
                //旋转
                degree += angle(cen,first,second)
                rotation = degree
            }
            MotionEvent.ACTION_UP -> {}
            else -> {}
        }

        return true
    }
    
    
    //获取角度
    private fun angle(cen: Point, first: Point, second: Point): Float {
        val dx1: Float = (first.x - cen.x).toFloat()
        val dy1: Float = (first.y - cen.y).toFloat()
        val dx2: Float = (second.x - cen.x).toFloat()
        val dy2: Float = (second.y - cen.y).toFloat()

        // 计算三边的平方
        val ab2 =
            ((second.x - first.x) * (second.x - first.x) + (second.y - first.y) * (second.y - first.y)).toFloat()
        val oa2 = dx1 * dx1 + dy1 * dy1
        val ob2 = dx2 * dx2 + dy2 * dy2

        // 根据两向量的叉乘来判断顺逆时针
        val isClockwise =
            (first.x - cen.x) * (second.y - cen.y) - (first.y - cen.y) * (second.x - cen.x) > 0
        // 根据余弦定理计算旋转角的余弦值
        var cosDegree =
            (oa2 + ob2 - ab2) / (2 * Math.sqrt(oa2.toDouble()) * Math.sqrt(ob2.toDouble()))

        // 异常处理,因为算出来会有误差绝对值可能会超过一,所以需要处理一下
        if (cosDegree > 1) {
            cosDegree = 1.0
        } else if (cosDegree < -1) {
            cosDegree = -1.0
        }

        // 计算弧度
        val radian = acos(cosDegree)

        // 计算旋转过的角度,顺时针为正,逆时针为负
        return (if (isClockwise) Math.toDegrees(radian) else -Math.toDegrees(radian)).toFloat()
    }

XML中标签的使用,导致布局错乱

在Android Studio中,标签的使用,导致布局预览的时候,界面显示错乱,这时我们可以用tools:parentTag="自己定义的布局",可以避免因使用<merge>标签导致的布局排列错乱问题,同时可以在预览中查看自定义布局效果

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    tools:parentTag="com.xx.xx.xx.RulerLayout"
    android:layout_height="wrap_content">
    
</merge>

多线程AtomicInteger

在Kotlin中,AtomicInteger是一种特殊的数据类型,它可以保证多个线程对它进行操作时的原子性。这意味着AtomicInteger的值可以在多个线程之间安全地共享和修改,而不必担心竞态条件或数据不一致的问题

多线程CountDownLatch

在Java中,CountDownLatch是一种同步工具类,它可以让一个或多个线程等待其他线程完成操作后再执行。CountDownLatch通过一个计数器来实现这个功能,计数器的初始值可以通过构造函数来指定,当计数器的值为0时,等待线程将会被唤醒继续执行。CountDownLatch通常用于协调多个线程之间的操作,以确保它们按照预期的顺序执行

如果你想快速实现多任务的并发分合策略,CountDownLatch会是一个不错的选择,而且它是官方帮你封装好的

Kotlin中自定义View

在构造函数中需要加@JvmOverloads constructor 例如:

class GuidingPrinciple@JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
    View(context, attrs, defStyleAttr) {
}

Kotlin中List可用+代替add

一开始看别人代码,有点懵,后面查了资料才发现,kotlin中可以用+代替集合的add方法

val stringList = ArrayList<String>()
val name = "John"
//下面这句等同与stringList.add(name)
stringList + name

贴一下源码:

Android一些项目知识点整理_android_02

Kotlin中集合操作符

groupBy

根据分组函数对集合进行分组,返回分组结果 MapMap 中的 key 类型由分组函数决定, value 的类型是 List

groupBy 两个参数的函数会对集合元素的值进行转换,最终添加到 Map

例如我们需要对字符串按长度进行分组,那么 Mapkey 就是 Int 类型

val company = listOf("Google", "Microsoft", "IBM", "Apple", "Yahoo", "Alibaba", "Baidu")
// {6=[Google], 9=[Microsoft], 3=[IBM], 5=[Apple, Yahoo, Baidu], 7=[Alibaba]}
println(company.groupBy { it.length })Baidu], 7=[Alibaba]}
// 两个参数,给元素添加个_下标
// {6=[Google_], 9=[Microsoft_], 3=[IBM_], 5=[Apple_, Yahoo_, Baidu_], 7=[Alibaba_]}
println(company.groupBy({ it.length },{ it + "_" }))

flatMap

将集合中的元素根据转换函数得到新的值,并且将所有值铺平到新的集合中。与 map 不同的是,flatMap 的转换函数需要返回一个新的集合,并且会将转换后的值都铺平到集合中,所以如果有嵌套的集合转换成单层的集合时请使用 flatMap

val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.flatMap { listOf(it + it, it * it, it * it * it) }) // [2, 1, 1, 4, 4, 8, 6, 9, 27, 8, 16, 64, 10, 25, 125]
println(nestList.flatMap { item -> item.map { it * it } }) // [1, 4, 9, 16, 25, 36, 49]

map

根据转换函数进行转换元素,得到一个包含所有转换之后的元素的 List

val intList = listOf(1, 2, 3, 4, 5)
val nestList = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6, 7))
println(intList.map { it * it }) // [1, 4, 9, 16, 25]
println(nestList.map {  item -> item.map { it * it } }) // [[1, 4], [9, 16], [25, 36, 49]]

可以很明显看到 mapflatMap 的区别,flatMap 会铺平整个集合,而 map 只是将转换元素累计

indexOfFirst

indexOfFirst()是Kotlin标准库中的一个函数,它可以用于查找满足指定条件的第一个元素的索引。它接收一个Lambda表达式作为参数,该表达式接收一个元素作为输入,并返回一个布尔值,表示该元素是否满足条件。如果存在满足条件的元素,则返回该元素的索引;否则返回-1。

开源库

AndroidUtilCode

// if u use AndroidX, use the following
implementation 'com.blankj:utilcodex:1.31.1'

// Not in maintenance
implementation 'com.blankj:utilcode:1.30.7'

地址:

AndroidUtilCode

Glide

implementation 'com.github.bumptech.glide:glide:4.16.0'

地址:

bumptech/glide

单RecyclerView实现抖音二级评论

地址:

blackfrogxxoo/CommentDemo: 单RecyclerView简单实现的二级评论功能。 (github.com)

富文本编辑器

地址:

chinalwb/Android-Rich-text-Editor

Android 资源库

地址:

ColorfulCat/AndroidLibs:正在成为史上最全分类 Android 开源大全)

图片选择器

地址:

LuckSiege/PictureSelector: Picture Selector Library for Android or 图片选择器 (github.com)

FrameWork教程

地址:

yuandaimaahao/AndroidFrameworkTutorial: 写给应用开发的 Android Framework 教程

AOSP生成系统签名

地址:

getfatday/keytool-importkeypair: A shell script to import key/certificate pairs into an existing Java keystore

Google机器学习套件

地址:

机器学习套件 | ML Kit | Google for Developers

Android一些项目知识点整理_android_03

RxTool

dependencies {
  //基础工具库
  implementation 'com.github.tamsiree.RxTool:RxKit:2.6.3'
  //UI库
  implementation 'com.github.tamsiree.RxTool:RxUI:2.6.3'
  //相机库
  implementation 'com.github.tamsiree.RxTool:RxCamera:2.6.3'
  //功能库(Zxing扫描与生成二维码条形码)
  implementation 'com.github.tamsiree.RxTool:RxFeature:2.6.3'
  //ArcGis For Android工具库(API:100.1以上版本)
  implementation 'com.github.tamsiree.RxTool:RxArcGisKit:2.6.3'
  //支付模块(支付宝 微信)[暂为待优化模块,谨慎]
  implementation 'com.github.tamsiree.RxTool:RxPay:2.6.3'
}

作用:

工具类集合 | 支付宝支付 | 微信支付(统一下单) | 微信分享 | Zip4j压缩(支持分卷压缩与加密) | 一键集成UCrop选择圆形头像 | 一键集成二维码和条形码的扫描与生成 | 常用Dialog | WebView的封装可播放视频 | 仿斗鱼滑动验证码 | Toast封装 | 震动 | GPS | Location定位 | 图片缩放 | Exif 图片添加地理位置信息(经纬度) | 蛛网等级 | 颜色选择器 | ArcGis | VTPK

地址:

Tamsiree/RxTool

GSYVideoPlayer

地址:

CarGuo/GSYVideoPlayer