本文已同步发表于我的
微信大众号
,查找代码说
即可重视,欢迎与我沟通交流。
Kotlin
中扩展函数是一种允许在已有的类中增加新函数,而无需修改类定义或承继该类。经过运用扩展函数,咱们能够轻松地为现有代码增加新功能和增强功能,下面就罗列几个有用的扩展函数。
runCatching代替try catch
- try catch 办法:
try {
100 / 0
} catch (ex: Throwable) {
ex.printStackTrace()
}
- runCatching 办法:
runCatching { 100 / 0 }
.onFailure { ex -> ex.printStackTrace() }
假如不关心回来值,到这儿就结束了,运用起来是不是更简单一些。假如需求持续对lambda
表达式中的计算成果进行处理,那么持续往下看。
runCatching
是在Kotlin 1.3
版本新增的,看下源码:
@InlineOnly
@SinceKotlin("1.3")
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Throwable) {
Result.failure(e)
}
}
能够看到runCatching
函数是一个扩展函数,函数承受一个lambda
表达式block
作为参数,并在T
目标上履行这个lambda
表达式,函数内部帮咱们增加了try catch
。
- 假如
lambda
表达式成功履行并回来成果,则运用Result.success
将成果包装成Result
类型并回来; - 假如出现反常,则运用
Result.failure
将反常包装成Result
类型并回来。
看下 Result
里都有什么:
罗列一些Result
中的常用函数:
runCatching { 100 / 0 }
.onSuccess { value -> log("onSuccess:$value") } //runCatching{}中履行成功,并传入履行成果
.onFailure { exception -> log("onFailure:$exception") } //runCatching{}中履行失败,并传入exception
//.getOrDefault(0) //获取runCatching{}中履行的成果,假如是Failure直接回来默认值
.getOrElse { ex -> //获取runCatching{}中履行的成果,假如是Failure回来else内部的值。相比getOrDefault多了对exception的处理
log("exception:$ex")
100
}
//.getOrThrow()//获取runCatching{}中履行的成果,假如是Failure直接抛反常
//.getOrNull() //获取runCatching{}中履行的成果,假如是Failure回来null
//.exceptionOrNull() //假如有问题则回来exception;否则回来null
.run {
log("result:$this")
}
履行成果:
E/TTT: onFailure:java.lang.ArithmeticException: divide by zero
E/TTT: exception:java.lang.ArithmeticException: divide by zero
E/TTT: result:100
尽管100/0
抛出了反常,还是能够经过getOrElse
中从头赋值,并最终把值输出出来,假如需求其他处理,能够运用上述示例中的其他函数,按需运用即可。
假如改为runCatching { 100 / 2 }
,其他代码不变,则输出成果:
E/TTT: onSuccess:50
E/TTT: result:50
View的可见性
fun View?.visible() {
if (this?.visibility != View.VISIBLE) {
this?.visibility = View.VISIBLE
}
}
fun View?.invisible() {
if (this?.visibility != View.INVISIBLE) {
this?.visibility = View.INVISIBLE
}
}
fun View?.gone() {
if (this?.visibility != View.GONE) {
this?.visibility = View.GONE
}
}
运用它们:
val toolbar: Toolbar = findViewById(R.id.toolbar)
toolbar.visible() //设置visible
toolbar.invisible() //设置invisible
toolbar.gone() //设置gone
dp、sp、px之间相互转换
//dp转px
fun Number.dp2px(): Int {
return ScreenUtil.dp2px(MyApplication.getApplication(), toFloat())
}
//sp转px
fun Number.sp2px(): Int {
return ScreenUtil.sp2px(MyApplication.getApplication(), toFloat())
}
//px转dp
fun Number.px2dp(): Int {
return ScreenUtil.px2dp(MyApplication.getApplication(), toFloat())
}
//px转sp
fun Number.px2sp(): Int {
return ScreenUtil.px2sp(MyApplication.getApplication(), toFloat())
}
object ScreenUtil {
fun dp2px(@NonNull context: Context, dp: Float): Int {
val scale = context.resources.displayMetrics.density
return (dp * scale + 0.5f).toInt()
}
fun px2dp(@NonNull context: Context, px: Float): Int {
val scale = context.resources.displayMetrics.density
return (px / scale + 0.5f).toInt()
}
fun sp2px(@NonNull context: Context, spValue: Float): Int {
val fontScale = context.resources.displayMetrics.scaledDensity
return (spValue * fontScale + 0.5f).toInt()
}
fun px2sp(@NonNull context: Context, pxValue: Float): Int {
val fontScale = context.resources.displayMetrics.scaledDensity
return (pxValue / fontScale + 0.5f).toInt()
}
}
运用它们:
100.dp2px()
100.sp2px()
100.px2dp()
100.px2sp()
by lazy 代替findViewById
by lazy
是属性延迟托付,关于托付机制的用法拜见:Kotlin | 10分钟搞定by托付机制。
fun <T : View> Activity.id(id: Int) = lazy {
findViewById<T>(id)
}
Activity
中运用:
class DemoActivity : AppCompatActivity() {
private val mToolBar: Toolbar by id(R.id.toolbar)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_xxx)
}
}
经过by lazy
简化了控件的创立流程,避免每次创立都去调用findViewById(id)
,跟Butterknife
的用法很类似。
假如是在Fragment
中运用呢?首要Fragment
中并没有findViewById(id)
函数,所以需求略微改造一下:
interface IRootView {
fun rootView(): View
}
//留意,这儿声明的是IRootView的扩展函数
fun <T : View> IRootView.id(id: Int) = lazy {
this.rootView().findViewById<T>(id)
}
abstract class BaseFragment : Fragment(), IRootView {
private var mRootView: View? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
if (mRootView == null) {
mRootView = inflater.inflate(getLayoutId(), container, false)
}
return mRootView
}
override fun rootView(): View {
return mRootView!!
}
@LayoutRes
abstract fun getLayoutId(): Int
}
-
IRootView
接口中只有一个rootView()
办法,回来类型为android.view.View
。 - 扩展函数
id<T : View>()
是针对完成IRootView
的目标进行扩展的。该函数需求传入Int
类型参数表明控件ID
,在调用时会运用lazy
托付形式延迟初始化并回来T
类型(泛型)控件。 -
BaseFragment
承继自Fragment
而且完成了IRootview
接口。同时其内部也维护着mRootview
变量用于缓存视图,在onCreateView
办法中创立视图,并将其保存到变量mRootview
中以便后边复用。
子类Fragment
中运用:
class DemoFragment : BaseFragment() {
private val mToolBar: Toolbar by id(R.id.toolbar)
override fun getLayoutId(): Int = R.layout.fragment_demo
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mToolBar.xxx //能够直接运用了
}
}
Toast、Log
fun Activity.showToast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, msg, duration).show()
}
fun Activity.showToast(@StringRes msg: Int, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, msg, duration).show()
}
fun Fragment.showToast(msg: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(requireContext(), msg, duration).show()
}
fun Fragment.showToast(@StringRes message: Int, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(requireContext(), message, duration).show()
}
fun log(msg: String, tag: String = "TAG") {
if (!BuildConfig.DEBUG) return
Log.d(tag, msg)
}
运用它:
showToast(R.string.action_settings) //1
showToast("棒棒哒", Toast.LENGTH_LONG) //2
log("log展示") //3
欢迎扫描下方二维码
或查找微信大众号 代码说
, 重视我的微信大众号检查最新文章~