当前位置:网站首页>Kotlin practical skills you should know
Kotlin practical skills you should know
2022-06-23 17:54:00 【Be a happy yard farmer】
Preface
as everyone knows ,kotlin yes google To replace by pushing java Of android development language
kotlin Easy to use , At the same time, there are many grammatical sugars
This article mainly explains some practical kotlin skill
Custom rounded rectangle
In the project , We often have to define rounded rectangular backgrounds , It is generally used to customize drawable Realized
However, the background and rounded corners of rounded rectangles often change slightly , And once it changes, we have to create a new one drawable file
This will cause the problem of file explosion
We can use kotlin The extension function of , To achieve a simple and convenient rounded rectangular background
fun View.setRoundRectBg(color: Int = Color.WHITE, cornerRadius: Int = 15.dp) {
background = GradientDrawable().apply {
setColor(color)
setCornerRadius(cornerRadius.toFloat())
}
}For those who need to customize the background View, Call directly setRoundRectBg that will do , Easy and convenient
reified Use
reified,kotlin Generic materialization keyword in , Make abstract things more concrete or real .
Let's give two examples to see how to use reified
startActivity Example
We generally startActivity It's written like this
startActivity(context, NewActivity::class.java)
We make use of reified Define an extension function
// Function
inline fun <reified T : Activity> Activity.startActivity(context: Context) {
startActivity(Intent(context, T::class.java))
}
// Caller
startActivity<NewActivity>(context)Use reified, Simplify generic parameters by adding type passing
In this way, there is no need to manually pass generic types
Gson Analyze the example
Let's first look at what we normally use gson analysis json How it's done
stay Java Serialization Library ( Such as Gson) in , When you want to deserialize the JSON When the string , You must eventually Class Object as a parameter , In order to Gson Know the type you want .
User user = new Gson().fromJson(getJson(), User.class)
Now? , Let's show reified The magic of type materialization parameters We will create a very lightweight extension function to wrap Gson Method :
inline fun <reified T> Gson.fromJson(json: String) =
fromJson(json, T::class.java)Now? , In our Kotlin In the code , We can deserialize JSON character string , You don't even need to pass type information at all !
val user: User = Gson().fromJson(json)
Kotlin Infer the type from its usage - Because we assign it to User Variable of type ,Kotlin Use it as fromJson() Type parameter of
kotin Interface support SAM transformation
What is? SAM transformation ? Some students may not know much about , Let's do some science popularization here :
SAM transformation , namely Single Abstract Method Conversions, For a transformation that has only a single non default abstract method interface —— For interfaces that meet this condition ( be called SAM Type ), stay Kotlin Can be used directly in Lambda To express —— Of course, the premise is Lambda The function type represented by can match the method in the interface .
stay Kotlin1.4 Before ,Kotlin It is not supported Kotlin Of SAM The conversion , Only support Java SAM transformation , The official explanation is : yes Kotlin It already has function types and higher-order functions , You don't have to go SAM conversion . Developers don't buy this explanation , If you used Java Lambda and Fuction Interface. When you switch to Kotlin when , Will be very confused . It seems Kotlin Is aware of this , Or see feedback from developers , Finally, I support it .
stay 1.4 Before , Only one object can be passed , It is not supported Kotlin SAM Of , And in the 1.4 after , Can support Kotlin SAM, But the usage has changed a bit .interface Need to use fun Keyword declaration . Use fun Keyword marks the interface , Just take this kind of interface as a parameter , It can be lambda Pass as a parameter .
// Attention needs fun Keyword declaration
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
fun main(){
// 1.4 Before , Only use object
runAction(object : Action{
override fun run() {
println("run action")
}
})
// 1.4-M1 Support SAM,OK
runAction {
println("Hello, Kotlin 1.4!")
}
}entrust
occasionally , The way to do some work is to delegate it to someone else . This is not to suggest that you entrust your work to your friends , It's about delegating the work of one object to another .
Of course , Delegation is not a new term in the software industry . entrust (Delegation) It's a design pattern , In this mode , Object delegates an assistant (helper) Object to handle the request , This helper object is called a proxy . The agent is responsible for processing the request on behalf of the original object , And make the results available to the original object .
Class delegation
for instance , When we want to implement an enhanced version of ArrayList, Support to restore the last deleted item
One way to implement this use case , It's inheritance ArrayList class . Because the new class inherits the concrete ArrayList Class, not implementation MutableList Interface , So it's with ArrayList The realization of high coupling .
If you just need to cover remove() Function to keep references to deleted items , And will MutableList The rest of the empty implementation is delegated to other objects , How nice that should be . In order to achieve this goal ,Kotlin Provides a way to delegate most of the work to an internal ArrayList Instance, and you can customize the way it behaves , A new keyword is introduced for this purpose : by.
<!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
class ListWithTrash <T>(private val innerList: MutableList<T> = ArrayList<T>()) : MutableCollection<T> by innerList {
var deletedItem : T? = null
override fun remove(element: T): Boolean {
deletedItem = element
return innerList.remove(element)
}
fun recover(): T? {
return deletedItem
}
}by Keyword telling Kotlin take MutableList The function of the interface is delegated to a innerList Internal ArrayList. By bridging to the inside ArrayList The way object methods ,ListWithTrash Still supported MutableList All functions in the interface . meanwhile , Now you can add your own behavior .
Property delegate
Except for class proxies , You can also use it by Keyword for attribute proxy . By using attribute proxies , The proxy class is responsible for handling the corresponding properties get And set Function call . This feature is used when you need to reuse between other objects getter/setter Logic is very useful , At the same time, you can easily expand the function of simple support fields
for instance , Delegate attributes can be used to encapsulate SharedPreference
Delegating data store operations to proxy classes has several benefits
1. The code is simplified , Convenient storage and read calls
2. And SP To understand the coupling , If you want to replace the repository later , Just modify the proxy class
Call the following :
object Pref: PreferenceHolder() {
var isFirstInstall: Boolean by bindToPreferenceField(false)
var time: Long? by bindToPreferenceFieldNullable()
}The specific implementation is visible :SharedPreferences use Kotlin It should be written like this
With state LiveData
At present, we use more and more in the development process MVVM Patterns and ViewModel
We often use LiveData To identify the network request status
We need to define the request start , The request is successful , request was aborted , Three LiveData
This is also very redundant code , So we can do some encapsulation , Encapsulate a stateful LiveData
The definition is as follows :
typealias StatefulLiveData<T> = LiveData<RequestState<T>>
typealias StatefulMutableLiveData<T> = MutableLiveData<RequestState<T>>
@MainThread
inline fun <T> StatefulLiveData<T>.observeState(
owner: LifecycleOwner,
init: ResultBuilder<T>.() -> Unit
) {
val result = ResultBuilder<T>().apply(init)
observe(owner) { state ->
when (state) {
is RequestState.Loading -> result.onLading.invoke()
is RequestState.Success -> result.onSuccess(state.data)
is RequestState.Error -> result.onError(state.error)
}
}
}Use as follows
val data = StatefulMutableLiveData<String>()
viewModel.data.observeState(viewLifecycleOwner) {
onLading = {
//loading
}
onSuccess = { data ->
//success
}
onError = { exception ->
//error
}
}Through the above packaging , It can encapsulate the network request gracefully and concisely loading,success,error state , Streamlined the code , The structure is also quite clear
DSL
DSL(domain specific language), Domain specific language : A computer language designed to solve a particular problem , For example, we are familiar with SQL And regular expressions .
however , If you create a separate language to solve a specific domain problem , Both development and learning costs are high , So there is the interior DSL The concept of . The so-called interior DSL, Is to use a general programming language to build DSL. such as , As mentioned in this article Kotlin DSL, We are Kotlin DSL Make a simple definition :
“ Use Kotlin Language development , Solve problems in specific areas , With unique code structure API .”
for instance , We use TabLayout when , If you want to add monitoring for him , You need to implement the following 3 A way
override fun onTabReselected(tab: TabLayout.Tab?){
}
override fun onTabUnselected(tab: TabLayout.Tab?){
}
override fun onTabSelected(tab: TabLayout.Tab?){
}In fact, we usually only use onTabSelected Method , The other two are generally empty implementations
We make use of DSL Yes OnTabSelectedListener encapsulate , You can avoid writing unnecessary empty implementation code
The specific implementation is as follows :
private typealias OnTabCallback = (tab: TabLayout.Tab?) -> Unit
class OnTabSelectedListenerBuilder : TabLayout.OnTabSelectedListener {
private var onTabReselectedCallback: OnTabCallback? = null
private var onTabUnselectedCallback: OnTabCallback? = null
private var onTabSelectedCallback: OnTabCallback? = null
override fun onTabReselected(tab: TabLayout.Tab?) =
onTabReselectedCallback?.invoke(tab) ?: Unit
override fun onTabUnselected(tab: TabLayout.Tab?) =
onTabUnselectedCallback?.invoke(tab) ?: Unit
override fun onTabSelected(tab: TabLayout.Tab?) =
onTabSelectedCallback?.invoke(tab) ?: Unit
fun onTabReselected(callback: OnTabCallback) {
onTabReselectedCallback = callback
}
fun onTabUnselected(callback: OnTabCallback) {
onTabUnselectedCallback = callback
}
fun onTabSelected(callback: OnTabCallback) {
onTabSelectedCallback = callback
}
}
fun registerOnTabSelectedListener(function: OnTabSelectedListenerBuilder.() -> Unit) =
OnTabSelectedListenerBuilder().also(function)Definition DSL The general steps of :
- 1. First define a class to implement the callback interface , And implement its callback method .
- 2. Observe the parameters of the callback method , Extract into a function type (function type), And use the type alias to give the function type another name as needed , And decorate with private .
- 3. Declare some mutable functions of nullable types in the class (var) Private member variables , And get the corresponding variable in the callback function to realize its invoke function , Pass in the corresponding parameter .
- 4. Define some names in the class that are the same as the callback interface , But the parameter is a function of the corresponding function type , And assign the function type to the corresponding member variable of the current class .
- 5. Define a member function , Parameter is a receiver object with the class we specified and returns Unit Of Lambda expression , Create the corresponding object in the function , And use also Function Lambda Pass in the expression .
Call the following :
tabLayout.addOnTabSelectedListener(registerOnTabSelectedListener {
onTabSelected { vpOrder.currentItem = it?.position ?: 0 }
})Above , You can avoid writing some unnecessary empty implementation code
边栏推荐
- How to open an account through online stock? Is online account opening safe?
- Postgresql_ Optimize SQL based on execution plan
- 数据库 实验二 查询
- Revil - blackmail Virus Emergency Response
- Android kotlin exception handling
- C#与数据库连接
- Goframe framework: graceful closing process
- MySQL事务提交流程
- Nanny level teaching! Take you to play with time complexity and space complexity!
- 10分钟后性能测试瓶颈调优!想进大厂这个必须会
猜你喜欢

Easyplayer mobile terminal plays webrtc protocol for a long time. Pressing the play page cannot close the "about us" page

qYKVEtqdDg
![[30. concatenate substrings of all words]](/img/e7/453c8524a23fbb7501e85140547ce1.png)
[30. concatenate substrings of all words]

10分钟后性能测试瓶颈调优!想进大厂这个必须会

How important is 5g dual card dual access?
![[untitled] Application of laser welding in medical treatment](/img/c5/9c9edf1c931dfdd995570fa20cf7fd.png)
[untitled] Application of laser welding in medical treatment

微信小程序:酒店预计到店日期的时间选择器

QT当中的【QSetting和.ini配置文件】以及【创建Resources.qrc】

【网络通信 -- WebRTC】WebRTC 源码分析 -- 接收端带宽估计

EasyPlayer移动端播放webrtc协议时长按播放页面无法关闭“关于我们”页面
随机推荐
C. Phoenix and Towers-Codeforces Global Round 14
数据库 实验二 查询
Li Kou daily question - day 25 -495 Timo attack
What is the problem with TS File Error 404 when easynvr plays HLS protocol?
The principle of MySQL index algorithm and the use of common indexes
MySQL installation, configuration and uninstall
How to quickly obtain and analyze the housing price in your city?
浅析3种电池容量监测方案
MySQL - reasons for using repeatable read
Tencent Qianfan scene connector: worry and effort saving automatic SMS sending
一文入门智能开关的3种功能形态
Postgresql_ Optimize SQL based on execution plan
Importance of ERP management system
B. Integers Shop-Hello 2022
qYKVEtqdDg
7、VLAN-Trunk
【网络通信 -- WebRTC】WebRTC 源码分析 -- 接收端带宽估计
How to use SQL window functions
[untitled] Application of laser welding in medical treatment
[go] calling Alipay to scan code for payment in a sandbox environment