第一次接触 Kotlin
仍是 2017 年,当时 Kotlin 还没扶正,也不是 Android 的官方开发语言。至于我是怎么被安利的,没记错的话,应该是 开源实验室 的 Kotlin 教程。当时身边几乎没有人在学 Kotlin,网上相关的资料也不多,我还翻译了一部分官网文档,写了一本 GitBook 。 固然如今有更好的 Kotlin 语言中文站 了,对于英文基础不是很好的同窗,这是一个不错的入门资料。java
两年半时间过来了,Kotlin 摇身一变,稳坐 Android 官方开发语言。尽管多是为了不与 Oracle 的诉讼,但我相信这绝对不是主要缘由。被定义为 Better Java
的 Kotlin,的确作到了更好,也逐渐为更多人所使用。android
愈来愈多的知名三方库都已经开始提供对 Kotlin 的支持。Android 官方的新特性也将优先支持 Kotlin。除了 Android 领域,Spring 5
正式发布时,也将 Kotlin 做为其主打的新特性之一。肉眼可见的,在 JVM 语言领域,Kotlin 必将有一番做为。浏览器
我在以前的一篇文章 真香!Kotlin+MVVM+LiveData+协程 打造 Wanandroid! 中开源了 Kotlin MVVM 版本的 Wanandroid 应用,到如今一共有 138
个 star 和 20
个 fork。数据并非多亮眼,但算是我开源生涯中的一大步。这个项目我也一直在更新,欢迎你们持续关注。安全
目前的工做中,除非一些不可抗拒因素,我已经将 Kotlin 做为第一选择。在进行多个项目的开发工做以后,我发现我常常在各个项目之间拷贝代码,base 类,扩展函数,工具类等等。甚至有的时候会翻回之前的 Java 代码,或者 Blankj 的 AndroidUtilCode,拿过来直接使用。可是不少时候直接生搬硬套 Java 工具类,并非那么的优雅,也没有很好的运用 Kotlin 语言特性。我迫切须要一个通用的 Kotlin 工具类库。bash
基于此,AndroidUtilCodeKTX 诞生了。若是你用过 Blankj 的 AndroidUtilCode
,它们的性质是同样的,但毫不是其简单的 Kotlin 翻译版本,而是更多的糅合了 Kotlin 特性,一切从 “简” ,代码越少越好。Talk is easy,show me the code !
话很少说,下面就代码展现 AndroidUtilCodeKTX 中一些工具类的使用。微信
request(Manifest.permission.READ_CALENDAR, Manifest.permission.RECORD_AUDIO) {
onGranted { toast("onGranted") }
onDenied { toast("onDenied") }
onShowRationale { showRationale(it) }
onNeverAskAgain { goToAppInfoPage() }
}
复制代码
借助扩展函数和 DSL ,能够轻松的在 Activity 中优雅的请求权限以及处理回调。这不是一个全新的轮子,主要代码来自 PermissionsKt 。可是它有一个致命的缺点,须要开发者手动覆写 onRequestPermissionsResult()
来处理权限请求结果,这显得并非那么简洁和优雅。我这里借鉴了 RxPermissions 的处理方式,经过在当前 Activity 依附一个 Fragment 进行权限请求以及回调处理,这样对用户来讲是无感的,且避免了额外的代码。后续会单独写一篇文章,分析其中 Kotlin DSL 的应用。app
putSpValue("int", 1)
putSpValue("float", 1f)
putSpValue("boolean", true)
putSpValue("string", "ktx")
putSpValue("serialize", Person("Man", 3))
getSpValue("int", 0)
getSpValue("float", 0f)
getSpValue(key = "boolean", default = false)
getSpValue("string", "null")
getSpValue("serialize", Person("default", 0))
复制代码
基本的存储和读取操做都只须要一个函数便可完成,依赖泛型无需主动声明值的类型。默认存储文件名称为包名,若是你想自定义文件名称,声明 name
参数便可:函数
putSpValue("another","from another sp file",name = "another")
getSpValue("another","null",name = "another")
复制代码
主要是优化了 startActivity
的使用,争取作到任何状况下均可以一句代码启动 Activity。
普通跳转:
startKtxActivity<AnotherActivity>()
复制代码
带 flag 跳转:
startKtxActivity<AnotherActivity>(Intent.FLAG_ACTIVITY_NEW_TASK)
复制代码
startActivityForResult :
startKtxActivityForResult<AnotherActivity>(requestCode = 1024)
复制代码
带值跳转:
startKtxActivity<AnotherActivity>(value = "string" to "single value")
复制代码
带多个值跳转:
startKtxActivity<AnotherActivity>(
values = arrayListOf(
"int" to 1,
"boolean" to true,
"string" to "multi value"
)
)
复制代码
带 Bundle 跳转:
startKtxActivity<AnotherActivity>(
extra = Bundle().apply {
putInt("int", 2)
putBoolean("boolean", true)
putString("string", "from bundle")
}
)
复制代码
基本涵盖了全部的 Activity 跳转状况。
ByteArray.aesEncrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray
ByteArray.aesDecrypt(key: ByteArray, iv: ByteArray, cipherAlgotirhm: String = AES_CFB_NOPADDING): ByteArray
File.aesEncrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File?
File.aesDecrypt(key: ByteArray, iv: ByteArray, destFilePath: String): File?
复制代码
封装了 Aes 加密操做,提供了快捷的数据和文件加解密方法,无需关注内部细节。默认使用 AES/CFB/NoPadding
模式,你能够经过 cipherAlgotirhm
参数修改模式。
plainText.toByteArray().aesEncrypt(key, iv, "AES/CBC/PKCS5Padding"
plainText.toByteArray().aesEncrypt(key, iv, "AES/ECB/PKCS5Padding"
plainText.toByteArray().aesEncrypt(key, iv, "AES/CTR/PKCS5Padding"
复制代码
给 String
和 ByteArray
提供了扩展方法,能够快捷的进行哈希。
ByteArray.hash(algorithm: Hash): String
String.hash(algorithm: Hash, charset: Charset = Charset.forName("utf-8")): String
ByteArray.md5Bytes(): ByteArray
ByteArray.md5(): String
String.md5(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha1Bytes(): ByteArray
ByteArray.sha1(): String
String.sha1(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha224Bytes(): ByteArray
ByteArray.sha224(): String
String.sha224(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha256Bytes(): ByteArray
ByteArray.sha256(): String
String.sha256(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha384Bytes(): ByteArray
ByteArray.sha384(): String
String.sha384(charset: Charset = Charset.forName("utf-8")): String
ByteArray.sha512Bytes(): ByteArray
ByteArray.sha512(): String
String.sha512(charset: Charset = Charset.forName("utf-8")): String
File.hash(algorithm: Hash = Hash.SHA1): String
复制代码
支持 MD5
, sha1
, sha224
, sha256
, sha384
, sha512
。MD5
已经再也不安全,密码学上来讲已经再也不推荐使用。
val origin = "hello"
val md5 = origin.hash(Hash.MD5)
val sha1 = origin.hash(Hash.SHA1)
复制代码
除了字符串取哈希,还提供了对文件取哈希值操做。
val file = File("xxx")
val md5 = file.hash(Hash.MD5)
val sha1 = file.hash(Hash.SHA1)
复制代码
跳转到应用信息界面:
Context.goToAppInfoPage(packageName: String = this.packageName)
复制代码
跳转到日期和时间页面:
Context.goToDateAndTimePage()
复制代码
跳转到语言设置页面:
Context.goToLanguagePage()
复制代码
跳转到无障碍服务设置页面:
Context.goToAccessibilitySetting()
复制代码
浏览器打开指定网页:
Context.openBrowser(url: String)
复制代码
安装 apk :
// need android.permission.REQUEST_INSTALL_PACKAGES after N
Context.installApk(apkFile: File)
复制代码
在应用商店中打开应用:
Context.openInAppStore(packageName: String = this.packageName)
复制代码
启动 App :
Context.openApp(packageName: String)
复制代码
卸载 App :(好像并无什么用)
Context.uninstallApp(packageName: String)
复制代码
fun String.logv(tag: String = TAG) = log(LEVEL.V, tag, this)
fun String.logd(tag: String = TAG) = log(LEVEL.D, tag, this)
fun String.logi(tag: String = TAG) = log(LEVEL.I, tag, this)
fun String.logw(tag: String = TAG) = log(LEVEL.W, tag, this)
fun String.loge(tag: String = TAG) = log(LEVEL.E, tag, this)
private fun log(level: LEVEL, tag: String, message: String) {
when (level) {
LEVEL.V -> Log.v(tag, message)
LEVEL.D -> Log.d(tag, message)
LEVEL.I -> Log.i(tag, message)
LEVEL.W -> Log.w(tag, message)
LEVEL.E -> Log.e(tag, message)
}
}
复制代码
tag
默认为 ktx
,你也能够在参数中本身指定。
"abc".logv()
"def".loge(tag = "xxx")
复制代码
原来咱们是这样获取系统服务的:
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
复制代码
其实也挺简洁的,可是咱们忘记了 Context.WINDOW_SERVICE
咋办?经过扩展属性可让它更优雅。
val Context.powerManager get() = getSystemService<PowerManager>()
inline fun <reified T> Context.getSystemService(): T? =
ContextCompat.getSystemService(this, T::class.java)
复制代码
对于用户来讲,直接使用 powerManager
便可,无需任何额外工做。
已做为扩展属性的系统服务以下:
val Context.windowManager
val Context.clipboardManager
val Context.layoutInflater
val Context.activityManager
val Context.powerManager
val Context.alarmManager
val Context.notificationManager
val Context.keyguardManager
val Context.locationManager
val Context.searchManager
val Context.storageManager
val Context.vibrator
val Context.connectivityManager
val Context.wifiManager
val Context.audioManager
val Context.mediaRouter
val Context.telephonyManager
val Context.sensorManager
val Context.subscriptionManager
val Context.carrierConfigManager
val Context.inputMethodManager
val Context.uiModeManager
val Context.downloadManager
val Context.batteryManager
val Context.jobScheduler
复制代码
Context.versionName: String
Context.versionCode: Long
Context.getAppInfo(apkPath: String): AppInfo
Context.getAppInfos(apkFolderPath: String): List<AppInfo>
Context.getAppSignature(packageName: String = this.packageName): ByteArray?
复制代码
这一块内容暂时还比较少,主要是整理了我在项目中遇到的一些常见需求。获取版本号,版本名称,根据 apk 文件获取应用信息,获取应用签名等等。App 相关的其实会有不少工具类,后续会慢慢补充。
View.visible()
View.invisible()
View.gone()
var View.isVisible: Boolean
var View.isInvisible: Boolean
var View.isGone: Boolean
View.setPadding(@Px size: Int)
View.postDelayed(delayInMillis: Long, crossinline action: () -> Unit): Runnable
View.toBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap
复制代码
也都是一些比较经常使用的函数。
Context.dp2px(dp: Float): Int
Context.px2dp(px: Float): Int
View.dp2px(dp: Float): Int
View.px2dp(px: Float): Int
Context.screenWidth
Context.screenHeight
Context.copyToClipboard(label: String, text: String)
复制代码
RecyclerView.itemPadding(top: Int, bottom: Int, left: Int = 0, right: Int = 0)
ByteArray.toHexString(): String
......
复制代码
implementation 'luyao.util.ktx:AndroidUtilKTX:0.0.5'
复制代码
以上都是我在项目中提炼出来的,也正因如此,如今的 AndroidUtilCodeKTX 还只是个孩子,作不到那么的尽善尽美,面面俱到。我会持续更新完善这个库,也但愿你们能够多多提 issue 和 pr,提供您宝贵的意见!
在这里也十分感谢 Jie Smart 昨天的邮件反馈,提供了一些修改意见,也让我更有动力去继续维护。另外,最新版本的 AndroidUtilCodeKTX 我都会第一时间用在个人开源项目 wanandroid 上,欢迎你们 star ,fork !
文章首发微信公众号:
秉心说
, 专一 Java 、 Android 原创知识分享,LeetCode 题解。更多相关知识,扫码关注我吧!