Android KTX Jake Wharton
A presentation at Google I/O 2018 in May 2018 in Mountain View, CA, USA by Jake Wharton
Android KTX Jake Wharton
Android KTX Jake Wharton
val userLayout :
ViewGroup
= findViewById ( R . id . users )
for
( index in
0
until userLayout . childCount )
{
userLayout . getChildAt ( index )
// Do something with index and view…
}
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} val userLayout :
ViewGroup
= findViewById ( R . id . users )
for
( index in
0
until userLayout . childCount )
{
userLayout . getChildAt ( index )
// Do something with index and view…
} A
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} val userLayout :
ViewGroup
= findViewById ( R . id . users )
for
( index in
0
until userLayout . childCount )
{
userLayout . getChildAt ( index )
// Do something with index and view…
} A
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
for
( index in
0
until userLayout . childCount )
{ G
userLayout . getChildAt ( index )
// Do something with index and view…
} A
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{ G index , view ->
// Do something with index and view…
} A
for ( in 0 until . childCount ) val = userLayout . getChildAt ( index )
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{ G index , view ->
// Do something with index and view…
} A
fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{ G index , view ->
// Do something with index and view…
} A
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{ G index , view ->
// Do something with index and view…
} A
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} D
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{ G index , view ->
// Do something with index and view…
} A
// In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java )
// In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java )
// or all API levels…
ContextCompat . getSystemService ( this ,
NotificationManager :: class . java )
// In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java )
// or all API levels…
ContextCompat . getSystemService ( this ,
NotificationManager :: class . java ) inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java )
// or all API levels…
ContextCompat . getSystemService ( this ,
NotificationManager :: class . java )
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java )
// or all API levels…
ContextCompat . getSystemService ( this ,
NotificationManager :: class . java )
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…
getSystemService ( NotificationManager :: class . java ) H
// or all API levels…
ContextCompat . getSystemService ( this ,
NotificationManager :: class . java )
s
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
// In an Activity…
systemService < NotificationManager
() H
S
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
// In an Activity…
systemService < NotificationManager
() H
avatarView . setPadding (
10 , avatarView . paddingTop , 10 , avatarView . paddingBottom )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} avatarView.setPadding (
10 , avatarView . paddingTop ,
10 , avatarView . paddingBottom )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} avatarView.setPadding (
10 , avatarView . paddingTop ,
10 , avatarView . paddingBottom )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
avatarView.setPadding (
10 , avatarView . paddingTop ,
10 , avatarView . paddingBottom ) R update
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
avatarView. updatePadding ( 10 ,
10 ) R
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
avatarView. updatePadding ( 10 ,
10 ) R
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
avatarView . clipBounds
rect . left
rect . top
rect . right
rect . bottom
// Use left, top, right, bottom…
avatarView . clipBounds
rect . left
rect . top
rect . right
rect . bottom
// Use left, top, right, bottom… inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
avatarView . clipBounds
rect . left
rect . top
rect . right
rect . bottom
// Use left, top, right, bottom…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
avatarView . clipBounds
rect . left
rect . top
rect . right
rect . bottom
// Use left, top, right, bottom…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
avatarView . clipBounds
rect . left
rect . top
rect . right
rect . bottom
// Use left, top, right, bottom…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
val
( left , T top , R right , B bottom )
= avatarView . clipBounds
// Use left, top, right, bottom…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
val
( left , T top , R right )
= avatarView . clipBounds
// Use left, top, right…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
val
( left , T _ , R right )
= avatarView . clipBounds
// Use left, right…
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
val
( left , T _ , R right )
= avatarView . clipBounds
// Use left, right…
var
onlyDigits
=
true
for
( c in phoneNumber )
{ A
if
(! c . isDigit ())
{
onlyDigits
=
false
break
} G
} B
phoneNumber . all
{ A it . isDigit ()
} B r true for ( c in ) if (! c . ) { onlyDigits = false break } G
TextUtils . isDigitsOnly ( phoneNumber ) . all { A it . isDigit () } B
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
TextUtils . isDigitsOnly ( phoneNumber ) L
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
phoneNumber . isDigitsOnly () L
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
phoneNumber .
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
phoneNumber .
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
phoneNumber . is
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
phoneNumber . is
inline
fun
CharSequence . isDigitsOnly ()
=
phoneNumber . isDigitsOnly () L
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
core-ktx Android KTX
Android KTX core-ktx Android framework
Android KTX Android framework support-compat core-ktx
Android KTX Android framework core core-ktx
Android KTX Android framework core core-ktx fragment-ktx fragment palette-ktx palette collection-ktx collection lifecycle-reactivestreams-ktx lifecycle-reactivestreams sqlite-ktx sqlite navigation--ktx navigation- work-runtime-ktx work-runtime
Android KTX Android framework core core-ktx fragment-ktx fragment palette-ktx palette collection-ktx collection lifecycle-reactivestreams-ktx lifecycle-reactivestreams sqlite-ktx sqlite navigation--ktx navigation- work-runtime-ktx work-runtime
@RequiresApi ( 26 )
operator
fun
Color . plus ( c :
Color ):
Color
{
if
( colorSpace
!= c . colorSpace ) c . convert ( colorSpace )
else c
s . components
components
s . alpha ()
// Destination alpha pre-composited
alpha ()
( 1.0f
sa )
// Index of the alpha component
componentCount
1
// Final alpha: src_alpha + dst_alpha * (1 - src_alpha)
dst
[ ai ]
= sa + da
// Divide by final alpha to return non pre-multiplied color
if
( dst [ ai ]
0 )
{
sa /
= dst [ ai ]
da /
= dst [ ai ]
}
// Composite non-alpha components
for
( i in
0
until ai )
{
dst
[ i ]
= src [ i ]
sa + dst [ i ]
da
}
return
Color . valueOf ( dst ,
colorSpace )
}
@RequiresApi ( 26 )
operator
fun
Color . plus ( c :
Color ):
Color
{
if
( colorSpace
!= c . colorSpace ) c . convert ( colorSpace )
else c
s . components
components
s . alpha ()
// Destination alpha pre-composited
alpha ()
( 1.0f
sa )
// Index of the alpha component
componentCount
1
// Final alpha: src_alpha + dst_alpha * (1 - src_alpha)
dst
[ ai ]
= sa + da
// Divide by final alpha to return non pre-multiplied color
if
( dst [ ai ]
0 )
{
sa /
= dst [ ai ]
da /
= dst [ ai ]
}
// Composite non-alpha components
for
( i in
0
until ai )
{
dst
[ i ]
= src [ i ]
sa + dst [ i ]
da
}
return
Color . valueOf ( dst ,
colorSpace )
}
@RequiresApi ( 26 )
operator
fun
Color . plus ( c :
Color ):
Color
{
if
( colorSpace
!= c . colorSpace ) c . convert ( colorSpace )
else c
s . components
components
s . alpha ()
// Destination alpha pre-composited
alpha ()
( 1.0f
sa )
// Index of the alpha component
componentCount
1
// Final alpha: src_alpha + dst_alpha * (1 - src_alpha)
dst
[ ai ]
= sa + da
// Divide by final alpha to return non pre-multiplied color
if
( dst [ ai ]
0 )
{
sa /
= dst [ ai ]
da /
= dst [ ai ]
}
// Composite non-alpha components
for
( i in
0
until ai )
{
dst
[ i ]
= src [ i ]
sa + dst [ i ]
da
}
return
Color . valueOf ( dst ,
colorSpace )
}
public
final
class
ColorUtils
{
} Z
public
final
class
ColorUtils
{
@ColorInt
public
static
int compositeColors (
@ColorInt
int foreground ,
@ColorInt
int background )
{
// …
} X
} Z
public
final
class
ColorUtils
{
@ColorInt
public
static
int compositeColors (
@ColorInt
int foreground ,
@ColorInt
int background )
{
// …
} X
@RequiresApi ( 26 )
public
static
Color compositeColors (
Color foreground ,
Color background )
{
// …
} Y
} Z
@RequiresApi ( 26 )
operator
fun
Color . plus ( c :
Color ):
Color
{
if
( colorSpace
!= c . colorSpace ) c . convert ( colorSpace )
else c
s . components
components
s . alpha ()
// Destination alpha pre-composited
alpha ()
( 1.0f
sa )
// Index of the alpha component
componentCount
1
// Final alpha: src_alpha + dst_alpha * (1 - src_alpha)
dst
[ ai ]
= sa + da
// Divide by final alpha to return non pre-multiplied color
if
( dst [ ai ]
0 )
{
sa /
= dst [ ai ]
da /
= dst [ ai ]
}
// Composite non-alpha components
for
( i in
0
until ai )
{
dst
[ i ]
= src [ i ]
sa + dst [ i ]
da
}
return
Color . valueOf ( dst ,
colorSpace )
}
@RequiresApi ( 26 )
inline operator
fun
Color . plus ( c :
Color ):
Color
=
ColorUtils . compositeColors ( c ,
this )
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
KTX Principles
KTX Principles Adapt existing functionality and redirect features upstream
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this ) Z
operator
fun
ViewGroup . iterator ()
=
object
:
MutableIterator < View
{
private
var
index
=
0
override
fun hasNext ()
=
index
<
childCount
override
fun next ()
=
getChildAt ( index ++)
?:
throw
IndexOutOfBoundsException ()
override
fun remove ()
= removeViewAt (-- index )
}
operator
fun
ViewGroup . iterator ()
=
object
:
MutableIterator < View
{
private
var
index
=
0
override
fun hasNext ()
=
index
<
childCount
override
fun next ()
=
getChildAt ( index ++)
?:
throw
IndexOutOfBoundsException ()
override
fun remove ()
= removeViewAt (-- index )
} for
( view in userLayout )
{
// Do something with view…
}
operator
fun
ViewGroup . iterator ()
=
object
:
MutableIterator < View
{
private
var
index
=
0
override
fun hasNext ()
=
index
<
childCount
override
fun next ()
=
getChildAt ( index ++)
?:
throw
IndexOutOfBoundsException ()
override
fun remove ()
= removeViewAt (-- index )
} for
( view in userLayout )
{
// Do something with view…
}
operator
fun
ViewGroup . iterator ()
=
object
:
MutableIterator < View
{
private
var
index
=
0
override
fun hasNext ()
=
index
<
childCount
override
fun next ()
=
getChildAt ( index ++)
?:
throw
IndexOutOfBoundsException ()
override
fun remove ()
= removeViewAt (-- index )
} for
( view in userLayout )
{
// Do something with view…
}
KTX Principles Adapt existing functionality and redirect features upstream
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive
inline fun
ViewGroup . forEachIndexed ( action :
( Int , View )
->
Unit )
{
for
( index in
0
until
childCount )
{
action
( index , getChildAt ( index ))
} Z
} Z
val userLayout :
ViewGroup
= findViewById ( R . id . users )
userLayout . forEachIndexed
{
index , view ->
// Do something with index and view…
} A
inline
fun
< reified T
Context . systemService ()
=
ContextCompat . getSystemService ( this , T :: class . java )
// In an Activity…
systemService < NotificationManager
() H
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
inline operator
fun
Rect . component1 ()
=
left
inline operator
fun
Rect . component2 ()
=
top
inline operator
fun
Rect . component3 ()
=
right
inline operator
fun
Rect . component4 ()
=
bottom
val
( left , T _ , R right )
= avatarView . clipBounds
// Use left, right…
inline
fun
CharSequence . isDigitsOnly ()
=
phoneNumber . isDigitsOnly () L
operator
fun
ViewGroup . iterator ()
=
object
:
MutableIterator < View
{
private
var
index
=
0
override
fun hasNext ()
=
index
<
childCount
override
fun next ()
=
getChildAt ( index ++)
?:
throw
IndexOutOfBoundsException ()
override
fun remove ()
= removeViewAt (-- index )
} for
( view in userLayout )
{
// Do something with view…
}
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin
view . setOnClickListener {
// React to click…
} Z
fun
View . click ( listener :
( View )
->
Unit )
{
setOnClickListener
( listener )
} Y
view . setOnClickListener { P
// React to click…
} Z
fun
View . click ( listener :
( View )
->
Unit )
{
setOnClickListener
( listener )
} Y
view . setOnClickListener { P
// React to click…
} Z
c
fun
View . click ( listener :
( View )
->
Unit )
{
setOnClickListener
( listener )
} Y
view . click
{ P
// React to click…
} Z C
view . click
{ P
// React to click…
} Z view . setOnClickListener {
// React to click…
}
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin Code golf APIs to be as short as possible
if
( Build . VERSION . SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
inline
fun onApi ( level :
Int , body :
()
->
Unit )
{
if
( Build . VERSION . SDK_INT
= level )
{
body
()
} Z
}
if
( Build . VERSION . SDK_INT
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
inline
fun onApi ( level :
Int , body :
()
->
Unit )
{
if
( Build . VERSION . SDK_INT
= level )
{
body
()
} Z
} Q
if
( Build . VERSION . SDK_INT
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z onApi
inline
fun onApi ( level :
Int , body :
()
->
Unit )
{
if
( Build . VERSION . SDK_INT
= level )
{
body
()
} Z
} Q
onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z if
( Build . VERSION . SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
if
( SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
if
( SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
if
( SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z else { // Something …
}
onApi ( 19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z
if
( SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z else { // Something …
} L onApi ( 19 ) F { A
TransitionManager . beginDelayedTransition ( viewGroup )
} ,
if
( SDK_INT
=
19 )
{
TransitionManager . beginDelayedTransition ( viewGroup )
} Z else { // Something …
} L onApi ( 19 ,
{ A
TransitionManager . beginDelayedTransition ( viewGroup )
}, { T
// Something
…
}) F
if
( SDK_INT
=
28 )
{ // Fancy new thing …
}
else if ( SDK_INT
= 19 ) {
TransitionManager . beginDelayedTransition ( viewGroup )
} Z else { // Something …
} L onApi ( 19 ,
{ A
TransitionManager . beginDelayedTransition ( viewGroup )
}, Z { T
// Something
…
}) F
if
( SDK_INT
=
28 )
{ // Fancy new thing …
}
else if ( SDK_INT
= 19 ) {
TransitionManager . beginDelayedTransition ( viewGroup )
} Z else { // Something …
} L onApi ( 19 ,
{ A
TransitionManager . beginDelayedTransition ( viewGroup )
}, Z { T
// Something
…
}) F
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin Code golf APIs to be as short as possible
KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin Code golf APIs to be as short as possible Optimize for a single and/or specific use case
Android KTX Android framework core core-ktx fragment-ktx fragment palette-ktx palette collection-ktx collection lifecycle-reactivestreams-ktx lifecycle-reactivestreams sqlite-ktx sqlite navigation--ktx navigation- work-runtime-ktx work-runtime
Android KTX Android framework core core-ktx fragment-ktx fragment palette-ktx palette collection-ktx collection lifecycle-reactivestreams-ktx lifecycle-reactivestreams sqlite-ktx sqlite navigation--ktx navigation- work-runtime-ktx work-runtime
supportFragmentManager . beginTransaction ()
. replace ( android . R . id . content , userFragment )
. commit ()
inline
fun
FragmentManager . transaction (
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
transaction
. commit ()
} supportFragmentManager . beginTransaction ()
. replace ( android . R . id . content , userFragment )
. commit ()
inline
fun
FragmentManager . transaction (
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
transaction
. commit ()
} A
supportFragmentManager . beginTransaction ()
. replace ( android . R . id . content , userFragment )
t
. commit ()
inline
fun
FragmentManager . transaction (
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
transaction
. commit ()
} A
supportFragmentManager . transaction {
replace
( android . R . id . content , userFragment )
} Z
T
inline
fun
FragmentManager . transaction (
allowStateLoss
:
Boolean
=
false
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
if
( allowStateLoss ) transaction . commitAllowingStateLoss ()
else transaction . commit ()
} A
supportFragmentManager . transaction {
replace
( android . R . id . content , userFragment )
} Z
inline
fun
FragmentManager . transaction (
allowStateLoss
:
Boolean
=
false
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
if
( allowStateLoss ) transaction . commitAllowingStateLoss ()
else transaction . commit ()
} A
supportFragmentManager . transaction { G
replace
( android . R . id . content , userFragment )
} Z
inline
fun
FragmentManager . transaction (
allowStateLoss
:
Boolean
=
false ,
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
if
( allowStateLoss ) transaction . commitAllowingStateLoss ()
else transaction . commit ()
} A
supportFragmentManager . transaction ( allowStateLoss
=
true )
{ G
replace
( android . R . id . content , userFragment )
} Z
L7
ALOAD
3
INVOKEVIRTUAL androidx/fragment/app/ FragmentManager beginTransaction()
Landroidx/fragment/app/ FragmentTransaction ;
ASTORE
7
L8
ALOAD
7
LDC
16908290
ALOAD
2
INVOKEVIRTUAL
androidx/fragment/app/ FragmentTransaction replace( I Landroidx/fragment/app/ Fragment ; )
Landroidx/fragment/app/ FragmentTransaction ;
POP
L9
ALOAD
7
INVOKEVIRTUAL androidx/fragment/app/ FragmentTransaction
commitAllowingStateLoss()
I
POP
inline
fun
FragmentManager . transaction (
allowStateLoss
:
Boolean
=
false ,
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
if
( allowStateLoss ) transaction . commitAllowingStateLoss ()
else transaction . commit ()
} A
supportFragmentManager . transaction ( allowStateLoss
=
true )
{ G
replace
( android . R . id . content , userFragment )
} Z
inline
fun
FragmentManager . transaction (
now
:
Boolean
=
false ,
allowStateLoss
:
Boolean
=
false ,
body
:
FragmentTransaction .()
->
Unit
)
{
beginTransaction ()
transaction
. body ()
if
( now )
{
if
( allowStateLoss ) transaction . commitNowAllowingStateLoss ()
else transaction . commitNow ()
}
else
{
if
( allowStateLoss ) transaction . commitAllowingStateLoss ()
else transaction . commit ()
}
} A
Building Kotlin-friendly libraries
Building Kotlin-friendly libraries • Port public API or entire library to Kotlin
Building Kotlin-friendly libraries • Port public API or entire library to Kotlin
• Ship sibling artifact with Kotlin extensions
Building Kotlin-friendly libraries • Port public API or entire library to Kotlin
• Ship sibling artifact with Kotlin extensions
• ???
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
static
boolean isDigitsOnly ( CharSequence str )
{
str . length ();
// …
} Y
} Z
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
} Z
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
} Z
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
@ExtensionFunction
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
} Z
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
@ExtensionFunction
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
} Z
inline
fun
CharSequence . isDigitsOnly ()
=
TextUtils . isDigitsOnly ( this )
phoneNumber . isDigitsOnly ()
class
TextUtils
{
@ExtensionFunction
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
phoneNumber . isDigitsOnly ()
class
TextUtils
{
@ExtensionFunction
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
phoneNumber . isDigitsOnly ()
class
TextUtils
{
@ExtensionFunction
static
boolean isDigitsOnly ( @NonNull
CharSequence str )
{
str . length ();
// …
} Y
phoneNumber . isDigitsOnly () // in the bytecode we get val
TextUtils . isDigitsOnly ( phoneNumber )
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
class
View
{
void setPadding ( int left ,
int top ,
int right ,
int bottom )
{ /* … */ } B
} A
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
10 ) R
class
View
{
void setPadding (
@KtName ( "left" ) A int left ,
@KtName ( "top" ) A int top ,
@KtName ( "right" ) A int right ,
@KtName ( "bottom" ) A int bottom
)
{
/* … */ } B
} A
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
class
View
{
void setPadding (
@KtName ( "left" ) A @DefaultValue ( "paddingLeft" ) int left ,
@KtName ( "top" ) A @DefaultValue ( "paddingTop" ) int top ,
@KtName ( "right" ) A @DefaultValue ( "paddingRight" ) int right ,
@KtName ( "bottom" ) A @DefaultValue ( "paddingBottom" ) int bottom
)
{
/* … */ } B
} A
inline
fun
View . updatePadding (
left
:
Int
=
paddingLeft ,
top
:
Int
=
paddingTop ,
right
:
Int
=
paddingRight ,
bottom
:
Int
=
paddingBottom
)
{
setPadding
( left , top , right , bottom )
} A
class
View
{
void setPadding (
@KtName ( "left" ) @DefaultValue ( "paddingLeft" ) int left ,
@KtName ( "top" ) @DefaultValue ( "paddingTop" ) int top ,
@KtName ( "right" ) @DefaultValue ( "paddingRight" ) int right ,
@KtName ( "bottom" ) @DefaultValue ( "paddingBottom" ) int bottom
)
{
/* … */ } B
} A
10 ) R
class
View
{
void setPadding (
@KtName ( "left" ) @DefaultValue ( "paddingLeft" ) int left ,
@KtName ( "top" ) @DefaultValue ( "paddingTop" ) int top ,
@KtName ( "right" ) @DefaultValue ( "paddingRight" ) int right ,
@KtName ( "bottom" ) @DefaultValue ( "paddingBottom" ) int bottom
)
{
/* … */ } B
} A
10 ) R
update
class
View
{
void setPadding (
@KtName ( "left" ) @DefaultValue ( "paddingLeft" ) int left ,
@KtName ( "top" ) @DefaultValue ( "paddingTop" ) int top ,
@KtName ( "right" ) @DefaultValue ( "paddingRight" ) int right ,
@KtName ( "bottom" ) @DefaultValue ( "paddingBottom" ) int bottom
)
{
/* … */ } B
} A
10 ) R // in bytecode we get avatarView . setPadding (
10 , avatarView . paddingTop , 10 , avatarView . paddingBottom )
update
KEEP-110
KEEP-110 • @ExtensionFunction / @ExtensionProperty — Turn a static method with at least one argument into an extension function or an extension property.
KEEP-110 • @ExtensionFunction / @ExtensionProperty — Turn a static method with at least one argument into an extension function or an extension property. • • @DefaultValue — Default parameter values.
KEEP-110 • @ExtensionFunction / @ExtensionProperty — Turn a static method with at least one argument into an extension function or an extension property. • • @DefaultValue — Default parameter values. • • @KtName — An alternate name for methods, fields, and parameters for use by Kotlin code.
Building Kotlin-friendly libraries • Port public API or entire library to Kotlin
• Ship sibling artifact with Kotlin extensions
• ???
Building Kotlin-friendly libraries • Port public API or entire library to Kotlin
• Ship sibling artifact with Kotlin extensions
• KEEP-110 annotations
Android KTX Android framework core core-ktx fragment-ktx fragment palette-ktx palette collection-ktx collection lifecycle-reactivestreams-ktx lifecycle-reactivestreams sqlite-ktx sqlite navigation--ktx navigation- work-runtime-ktx work-runtime
https://github.com/Kotlin/KEEP/issues/110
Jake Wharton Thank you
@JakeWharton