1.0 前言
Android KTX
是Android
中的一组 Kotlin
扩展程序,可以为Android
开发提供简洁方便的 Kotlin
代码。
如果我们新建一个项目,可以发现,Core KTX
默认是被依赖到项目里的,能够说明Google对其的重视程度。
KTX
中的方法有很多,但平时都不知道哪些地方可以使用KTX
,这两天特意罗列了一下,在此记载。
1.1 添加依赖
dependencies {
implementation "androidx.core:core-ktx:1.9.0"
}
添加依赖后,我们可以在External Libraries
中看到ktx-core
中有这些包,下文会按照这些包的顺序进行罗列
1.2 animation
1.2.1 Animator.addListener
平时我们注册Animator
监听的时候,需要去实现其每一个方法
animator.addListener(object : Animator.AnimatorListener{
override fun onAnimationStart(animation: Animator?) {
Log.i(TAG,"onAnimationStart")
}
override fun onAnimationEnd(animation: Animator?) {
Log.i(TAG,"onAnimationEnd")
}
override fun onAnimationCancel(animation: Animator?) {
Log.i(TAG,"onAnimationCancel")
}
override fun onAnimationRepeat(animation: Animator?) {
Log.i(TAG,"onAnimationRepeat")
}
})
而使用KTX
我们可以只实现自己所需要的方法
val animator = ValueAnimator.ofInt(0, 100)
animator.addListener(onStart = {
Log.i(TAG,"onStart")
})
更多监听/回调的简化,详见我的另一篇文章 在Android中,简化冗长的监听/回调 写法
1.3 content
1.3.1 contentValuesOf
contentValuesOf用于将若干个Pair转化为ContentValues
val pair = Pair("key", true)
val pair2 = Pair("key2", "hello")
val contentValues = contentValuesOf(pair,pair2)
val result = contentValues.getAsBoolean("key")
val result2 = contentValues.getAsString("key2")
Log.i(TAG, "result:$result result2:$result2") //打印结果为result:true result2:heelo
ContentValues和Hash Table都是一种存储的机制。两者的区别在于,contentValues只能存储基本类型的数据,String,int之类的,不能存储对象,而Hash Table却可以存储对象。
把数据插入数据库中时,首先要有一个ContentValues的对象:
ContentValues contentValues = new ContentValues();
contentValues.put(key,values);
SQLiteDataBase sdb;
sdb.insert(database_name,null,initialValues);
成功插入则返回记录的id,否则返回-1。
1.3.2 ContextKt
1.3.2.1 Context.getSystemService()
可以不用再传入String,直接根据泛型返回Service,比如我们这里获取WindowManager
原本需要这样获取
val windowManager1 : WindowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
现在可以这样获取
val windowManager = getSystemService<WindowManager>()
1.3.2.2 Context.withStyledAttributes
自定义View中获取自定义属性
原本要这么写
val ta = context.obtainStyledAttributes(attrs, R.styleable.MyView)
val color = ta.getColor(R.styleable.MyView_titleTextColor, defColor)
ta.recycle()
现在可以这样写
context.withStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, defStyleAttr) {
val color = ta.getColor(R.styleable.MyView_titleTextColor,defColor)
}
1.3.3 SharedPreferencesKt
更简单的使用 SharedPreferences
val sharedPreferences = application.getSharedPreferences("sp", MODE_PRIVATE)
sharedPreferences.edit {
putBoolean("key", value) }
1.3.4 content.res
1.3.4.1 TypedArray
TypedArrayKt定义了很多getXXXXOrThrow
的扩展方法,我们看其内部代码,可以看到主要是在获取自定义属性之前,先去检查下这个属性是否存在,如果不存在,那就抛出异常。
我们以getBooleanOrThrow
为例
val ta: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.Topbar)
ta.getBooleanOrThrow()
ta.recycle()
来看下它源码
public fun TypedArray.getBooleanOrThrow(@StyleableRes index: Int): Boolean {
checkAttribute(index)
return getBoolean(index, false)
}
private fun TypedArray.checkAttribute(@StyleableRes index: Int) {
if (!hasValue(index)) {
throw IllegalArgumentException("Attribute not defined in set.")
}
}
可以看到,其获取自定义属性之前,都会先去调用hasValue
判断该属性是否存在。
1.4 database
1.4.1 SQLiteDatabaseKt
这个是用来简化Sqlite
数据库的,一般都直接用封装后的Room
了,不会直接调用这个方法
1.4.2 CursorKt
提供了一些可为空的获取
cursor.getDouble() //不可为空
cursor.getDoubleOrNull() //可为空
1.5 graphics.drawable
1.5.1 BitmapDrawableKt
1.5.1.1 Bitmap.toDrawable
将Bitmap转化为Drawable
val drawable = bitmap.toDrawable(resources)
1.5.2 ColorDrawableKt
1.5.2.1 Color.toDrawable
将Color
转化为Drawable
val drawable = color.toDrawable()
1.5.2.2 @ColorInt Int…toDrawable
将ColorInt
转化为Drawable
val drawable = R.color.black.toDrawable()
1.5.3 DrawableKt
1.5.3.1 Drawable.toBitmap
将Drawable
转化为Bitmap
val bitmap = drawable.toBitmap() //不为空
val bitmap = drawable.toBitmapOrNull() //可为空
1.5.3.2 Drawable.updateBounds
设置这个可绘制对象的边界
drawable.setBounds(100, 50, 150, 200) //原方法
drawable.updateBounds(100,50,150,200) //使用Ktx
1.5.4 Iconkt
将Bitmap
、Uri
、ByteArray
转化为Icon
Bitmap.toAdaptiveIcon(): Icon
Bitmap.toIcon(): Icon
Uri.toIcon(): Icon
ByteArray.toIcon(): Icon
1.6 graphics
1.6.1 BitmapKt
可以简化Bitmap
的创建
val bitmap = createBitmap(...).applyCanvas {
drawText(...)
drawLine(...)
drawRect(...)
}
val scaleBitmap = bitmap.scale(1280, 720) //创建缩放后的Bitmap
bitmap.contains(point)
bitmap.contains(pointF)
bitmap.get(10, 20) //获取指定位置的像素值
val color = resources.getColor(R.color.black)
bitmap.set(30, 50, color) //设置指定位置的像素颜色
1.6.2 CanvasKt
1.6.2.1 Canvas.withClip
使用闭包,无需自己再save() -> clip()
后,重置画布restoreToCoun()
val rect = RectF(100F, 50F, 200F, 150F)
canvas?.withClip(rect) {
this.drawArc()
this.drawText()
}
其他也是类似的
canvas?.withScale {
}
canvas?.withRotation {
}
canvas?.withSave {
}
canvas?.withMatrix {
}
canvas?.withSkew{
}
canvas?.withTranslation{
}
1.6.2.2 ColorKt
val color = R.color.teal_700
val alphaInt = color.component1() //相当于Color.alpha(),获取color的透明度
val redInt = color.component2() //相当于Color.red(),获取color的red值
val greenInt = color.component3() //Color.green(),获取color的green值
val blueInt = color.component4() //Color.blue(),获取color的blue值
val (alphaInt, redInt, greenInt, blueInt) = color //解构color,解构为透明度、red值,green值,blue值
1.6.3 ImageDecoderKt
// 利用Android9.0新增的ImageDecoder读取图片
val source: ImageDecoder.Source = ImageDecoder.createSource(contentResolver, imageUri)
// 从数据源解码得到图形信息
//原本的方式
val drawable: Drawable =
ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener {
override fun onHeaderDecoded(
decoder: ImageDecoder,
info: ImageDecoder.ImageInfo,
source: ImageDecoder.Source
) {
}
})
//Ktx的方式
val drawable: Drawable = source.decodeDrawable {
info, source -> }
ivPhoto.setImageDrawable(drawable) // 设置图像视图的图形对象
1.6.4 MatrixKt
Matrix的便捷操作
val rotationMatrix = rotationMatrix(...) //创建Matrix,并进行rotation操作
val scaleMatrix = scaleMatrix(...) //创建创建Matrix,并进行scale操作
val translationMatrix = translationMatrix(...) //创建创建Matrix,并进行translation操作
val newMatrix = rotationMatrix.times(scaleMatrix) //用这个矩阵乘以另一个矩阵并返回结果作为一个新矩阵
val matrixFloatArray = newMatrix.values() //获取矩阵的9个值,以长度为9的FloatArray数组表示
1.6.5 Pathkt
Path的便捷操作
val path1 = Path()
val path2 = Path()
val path3 = path1 + path2
val path4 = path1 - path2
val path5 = path1 or path2
val path6 = path1 xor path2
val path7 = path1 and path2
val flatten = path1.flatten(0.5F)
1.6.6 PointKt
Point的便捷操作
val point1 = Point()
val point2 = Point()
val point3 = point1 + point2
val point4 = point1 - point2
val pointF = point1.toPointF()
val point5 = pointF.toPoint()
val point6 = -point1 //unaryMinus
val x = point1.component1() //获取point1.X
val y = point1.component2() //获取point1.Y
val (x2, y2) = point2 //解构,获取X和Y
1.6.7 PorterDuff.Mode
图层混合模式PorterDuff.Mode便捷操作
val colorFilter = PorterDuff.Mode.SRC.toColorFilter(color)
val xferMode = PorterDuff.Mode.SRC.toXfermode()
1.6.8 RectKt
Rect的便捷操作
val rect1 = Rect()
val rect2 = Rect()
val rect3 = rect1 + rect2
val rect4 = rect1 - rect2
val rect5 = rect1 or rect2
val rect6 = rect1 xor rect2
val rect7 = rect1 and rect2
val contains = rect1.contains(rect2)
val rectF = rect1.toRectF()
val rect8 = rectF.toRect()
rect1.times(65) //等比例返回新Rect
rectF.times(0.12F)
val region99 = rect1.toRegion()
//rectF.transform(matrix) //根据matrix变化为新的RectF
val (left, top, right, bottom) = rect1 //解构,将rect拆分为left, top, right, bottom
1.6.9 RegionKt
Region的便捷操作
val region1 = Region()
val region2 = Region()
val region3 = region1 + region2
val region4 = region1 - region2
val region5 = region1 or region2
val region6 = region1 xor region2
val region7 = region1 and region2
val region8 = -region1 //unaryMinus
val region9 = !region1 //非运算
val iterator = region1.iterator()
region1.forEach {
}
region1.contains(point1)
1.6.10 Shader
着色器
transform
: 包装代码块之 Shader.getLocalMatrix
和Shader.setLocalMatrix
之间
val shader = Shader()
shader.transform {
this.setSkew() //this : Matrix
}
看下其内部实现
public inline fun Shader.transform(block: Matrix.() -> Unit) {
val matrix = Matrix()
getLocalMatrix(matrix)
block(matrix)
setLocalMatrix(matrix)
}
1.7 location
1.7.1 LocationKt
将Location解构为经度和维度
val location : android.location.Location = Location("")
val (lat,lng) = location
1.8 net
1.8.1 UriKt
Uri便捷使用
val uri1 = Uri.parse("content://media/external/images/media/4")
val uri2 = "content://media/external/images/media/4".toUri()
val file1 = uri1.toFile()
val uri3 = file1.toUri()
1.9 os
1.9.1 Bundlekt
Pair转Bundle
val bundle = bundleOf(Pair("key1", "value1"), Pair("key2", "value2")) //Bundle
val bundle2 = persistableBundleOf(Pair("key1", "value1"), Pair("key2", "value2")) //PersistableBundle
val map = HashMap<String,String>()
val bundle3 = map.toPersistableBundle()
1.9.2 OutcomeReceiverKt
这个和协程有关,暂时还没用过
1.9.3 HandlerKt
Handler便捷操作
val WHAT = 0x01
val handler = Handler()
handler.postAtTime(SystemClock.uptimeMillis(),WHAT) {
}
handler.postDelayed(1000L,WHAT) {
//回调放在最后
}
1.9.4 TraceKt
systrace 性能优化 : 结合Android内核的数据,生成Html报告
将代码块包装在TraceCompat.beginSection(sectionName)
和TraceCompat.endSection()
之间
trace("sectionName") {
//真正执行的代码,会统计这部分代码的执行时间等
}
1.9.5 CharSequenceKt
CharSequence的便捷使用
"hello".isDigitsOnly() //是否只包含数字,相当于 TextUtils.isDigitsOnly
"world".trimmedLength() //获取字符串去除头尾空格之后的长度,相当于 TextUtils.getTrimmedLength
1.9.6 HtmlKt
val spanned1 ="<html>....</html>".parseAsHtml()
val spanned : Spanned? = null
val html = spanned?.toHtml()
1.9.7 SpannableStringBuilder
便捷地创建富文本
val color = Global.getColor(R.color.teal_700)
val spannedString = buildSpannedString {
bold {
append("001")
}
color(color) {
append("002")
}
underline {
append("003")
}
backgroundColor(color) {
append("004")
}
italic {
append("005")
}
scale(1.5F) {
underline {
//可以多个组合一起使用
append("006")
}
}
strikeThrough {
//删除线
append("007")
}
subscript {
//下标
append("008")
}
superscript {
//上标
append("009")
}
append("010")
}
binding.tvInfo.text = spannedString
效果如下所示
1.9.8 SpannableStringKt
val spannable: Spannable? = null
spannable?.clearSpans()
spannable?.set(1, 5, StyleSpan(Typeface.BOLD_ITALIC))
val spannable1 = "qwerty".toSpannable()
1.9.9 SpannedStringKt
val spanned2: Spanned? = null
val spanned3 = spanned2?.getSpans<Spanned>(1, 6)
val spanned4 = "asdfgh".toSpanned()
1.9.10 StringKt
"xxxxx".htmlEncode() //相当于 TextUtils.htmlEncode
1.10 transition
1.10.1 TransitionKt
动画监听便捷设置
val startScene = Scene.getSceneForLayout(group, R.layout.activity_main_start, this)
val changeBounds = ChangeBounds()
TransitionManager.go(startScene, changeBounds)
changeBounds.addListener(
onStart = {
Log.i(TAG,"onStart")
},
onEnd = {
Log.i(TAG,"onEnd")
},
onCancel = {
Log.i(TAG,"onCancel")
},
onResume = {
Log.i(TAG,"onResume")
},
onPause = {
Log.i(TAG,"onPause")
})
也可以直接注册其某一个方法
changeBounds.doOnStart {
Log.i(TAG, "onOnStart")
}
changeBounds.doOnEnd {
Log.i(TAG, "onOnEnd")
}
changeBounds.doOnCancel {
Log.i(TAG, "onOnCancel")
}
changeBounds.doOnResume {
Log.i(TAG, "onOnResume")
}
changeBounds.doOnPause {
Log.i(TAG, "doOnPause")
}
更多监听/回调的简化,详见我的另一篇文章 在Android中,简化冗长的监听/回调 写法
1.11 util
1.11.1 AndroidXConsumerKt
这个和协程有关,暂时还没用过
1.11.2 AtomicFileKt
方便AtomicFile
的操作,AtomicFile
这个大家一般很少见到过这个类,我查了一下,AtomicFile
的作用 :
AtomicFile
保证文件的写入完成,并在写入之后删除备份文件。只要备份文件存在,那么原始文件之前遗留的操作是无效的。
1.11.3 ConsumerKt
这个和协程有关,暂时还没用过
1.11.4 HalfKt
方便转成Half
类型,Half
是个包装类型,可以进行浮点类型的转换
val half = 2.98F.toHalf()
val half2 = 3.926.toHalf()
val half3 = "5.9".toHalf()
1.11.5 LruCacheKt
可以用来便捷的创建LruCache
val lruCache = lruCache(...)
1.11.6 PairKt
使Pair
可以快速的进行解构,获得Key
和Value
val pair = Pair("key1", 1)
val (key, value) = pair
1.11.7 RangeKt
Range
用于描述两个数值的范围,没用过这个
1.11.8 RunnableKt
用来协程转Runnable
1.11.9 SizeKt
用来对Size
快速进行解构,获得width
和height
val size = Size(100,200)
val (width,height) = size
1.11.10 SparseArrayKt
包含SparseArrayKt / LongSparseArrayKt / SparseBooleanArrayKt / SparseIntArrayKt / SparseLongArrayKt
,操作都差不多,以下以SparseArray
为例
val sparseArray = SparseArray<String>()
sparseArray.append(1, "value1")
sparseArray.append(2, "value2")
sparseArray.append(3, "value3")
sparseArray.containsKey(1)
sparseArray.containsValue("value1")
sparseArray.forEach {
key, value ->
}
sparseArray.getOrDefault(4, "00004")
sparseArray.getOrElse(5) {
"00005"
}
sparseArray.isEmpty()
sparseArray.isNotEmpty()
val keyIterator = sparseArray.keyIterator()
val valueIterator = sparseArray.valueIterator()
val sparseArray2 = SparseArray<String>()
sparseArray2.set(9, "9999")
val sparseArray3 = sparseArray + sparseArray2
sparseArray3.remove(3, "value") //当值相等的之后执行remove
sparseArray.putAll(sparseArray2)
1.12 view
1.12.1 MenuKt
Menu便捷使用
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(com.heiko.mytest0930.R.menu.menu_main,menu)
val menuItem = menu?.get(0)
menu?.contains(menuItem!!)
menu?.forEach {
} //遍历Menu
menu?.forEachIndexed {
index, item -> }
menu?.isEmpty()
menu?.isNotEmpty()
val iterator = menu?.iterator()
menu?.removeItemAt(1)
return true
}
1.12.2 ViewGroupKt
val group = LinearLayout(this)
val childView = TextView(this)
group.contains(childView)
group.forEach {
}
group.forEachIndexed {
index, view -> }
group.get(1)
group.isEmpty()
group.isNotEmpty()
val iterator = group.iterator()
group.plusAssign(childView) //添加View,相当于 addView
group.minusAssign(childView) //删除View,相当于 removeView
val marginLayoutParams = group.layoutParams as MarginLayoutParams
marginLayoutParams.setMargins(10, 5, 10, 5)
marginLayoutParams.updateMargins(20, 0, 20, 0) //left、right
marginLayoutParams.updateMarginsRelative(30, 10, 30, 10) //start、end
1.12.3 ViewKt
val view = View(this)
view.doOnAttach {
}
view.doOnDetach {
}
view.doOnLayout {
}
view.doOnNextLayout {
}
view.doOnPreDraw {
}
view.setPadding(10,5,10,5)
val bitmap = view.drawToBitmap()
view.postDelayed(1000L) {
//回调放在最后
}
view.postOnAnimationDelayed(1000L){
}
view.updateLayoutParams<MarginLayoutParams> {
this.marginStart = 20
this.width = 200
}
view.updatePadding(20,10,20,10) //left、right
view.updatePaddingRelative(30,5,30,5) //start、end
1.13 widget
1.13.1 TextViewKt
TextView监听便捷设置
textView.addTextChangedListener(onTextChanged = {
text, start, before, count ->
Log.i(TAG,"onTextChanged:$text")
})
还可以直接注册其某一个方法
textView.doBeforeTextChanged {
text, start, count, after ->
Log.i(TAG, "onBeforeTextChanged:$text")
}
textView.doOnTextChanged {
text, start, before, count ->
Log.i(TAG, "onTextChange:$text")
}
textView.doAfterTextChanged {
Log.i(TAG, "onAfterTextChanged")
}
更多监听/回调的简化,详见我的另一篇文章 在Android中,简化冗长的监听/回调 写法
1.14 官方文档
附上官方文档链接 : Android KTX 官方文档