Android KTX

A presentation at Google I/O 2018 in May 2018 in Mountain View, CA, USA by Jake Wharton

Slide 1

Slide 1

Android KTX Jake Wharton

Slide 2

Slide 2

Android KTX Jake Wharton

Slide 3

Slide 3

val userLayout :

ViewGroup

= findViewById ( R . id . users )

for

( index in

0

until userLayout . childCount )

{

val view

userLayout . getChildAt ( index )

// Do something with index and view…

}

Slide 4

Slide 4

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 )

{

val view

userLayout . getChildAt ( index )

// Do something with index and view…

} A

Slide 5

Slide 5

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 )

{

val view

userLayout . getChildAt ( index )

// Do something with index and view…

} A

Slide 6

Slide 6

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

val view

userLayout . getChildAt ( index )

// Do something with index and view…

} A

Slide 7

Slide 7

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 )

Slide 8

Slide 8

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

Slide 9

Slide 9

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

Slide 10

Slide 10

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

Slide 11

Slide 11

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

Slide 12

Slide 12

// In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java )

Slide 13

Slide 13

// In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java )

// or all API levels…

val notifications

ContextCompat . getSystemService ( this ,

NotificationManager :: class . java )

Slide 14

Slide 14

// In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java )

// or all API levels…

val notifications

ContextCompat . getSystemService ( this ,

NotificationManager :: class . java ) inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java )

Slide 15

Slide 15

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java )

// or all API levels…

val notifications

ContextCompat . getSystemService ( this ,

NotificationManager :: class . java )

Slide 16

Slide 16

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java )

// or all API levels…

val notifications

ContextCompat . getSystemService ( this ,

NotificationManager :: class . java )

Slide 17

Slide 17

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java ) // In an Activity, on API 23+…

val notifications

getSystemService ( NotificationManager :: class . java ) H

// or all API levels…

val notifications

ContextCompat . getSystemService ( this ,

NotificationManager :: class . java )

             	  	   	 	s 

Slide 18

Slide 18

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java )

// In an Activity…

val notifications

systemService < NotificationManager

() H

               	 	 	 	S 

Slide 19

Slide 19

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java )

// In an Activity…

val notifications

systemService < NotificationManager

() H

Slide 20

Slide 20

avatarView . setPadding (

10 , avatarView . paddingTop , 10 , avatarView . paddingBottom )

Slide 21

Slide 21

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 )

Slide 22

Slide 22

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 )

Slide 23

Slide 23

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

Slide 24

Slide 24

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

Slide 25

Slide 25

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

Slide 26

Slide 26

inline

fun

View . updatePadding (

left

:

Int

=

paddingLeft ,

top

:

Int

=

paddingTop ,

right

:

Int

=

paddingRight ,

bottom

:

Int

=

paddingBottom

)

{

setPadding

( left , top , right , bottom )

} A

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 27

Slide 27

inline

fun

View . updatePadding (

left

:

Int

=

paddingLeft ,

top

:

Int

=

paddingTop ,

right

:

Int

=

paddingRight ,

bottom

:

Int

=

paddingBottom

)

{

setPadding

( left , top , right , bottom )

} A

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 28

Slide 28

val rect

avatarView . clipBounds

val left

rect . left

val top

rect . top

val right

rect . right

val bottom

rect . bottom

// Use left, top, right, bottom…

Slide 29

Slide 29

val rect

avatarView . clipBounds

val left

rect . left

val top

rect . top

val right

rect . right

val bottom

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

Slide 30

Slide 30

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 rect

avatarView . clipBounds

val left

rect . left

val top

rect . top

val right

rect . right

val bottom

rect . bottom

// Use left, top, right, bottom…

Slide 31

Slide 31

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 rect

avatarView . clipBounds

val left

rect . left

val top

rect . top

val right

rect . right

val bottom

rect . bottom

// Use left, top, right, bottom…

Slide 32

Slide 32

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 rect

avatarView . clipBounds

val left

rect . left

val T top

rect . top

val R right

rect . right

val B bottom

rect . bottom

// Use left, top, right, bottom…

Slide 33

Slide 33

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…

Slide 34

Slide 34

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…

Slide 35

Slide 35

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…

Slide 36

Slide 36

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…

Slide 37

Slide 37

var

onlyDigits

=

true

for

( c in phoneNumber )

{ A

if

(! c . isDigit ())

{

onlyDigits

=

false

break

} G

} B

Slide 38

Slide 38

val onlyDigits

phoneNumber . all

{ A it . isDigit ()

} B r true for ( c in ) if (! c . ) { onlyDigits = false break } G

Slide 39

Slide 39

val onlyDigits

TextUtils . isDigitsOnly ( phoneNumber ) . all { A it . isDigit () } B

Slide 40

Slide 40

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

TextUtils . isDigitsOnly ( phoneNumber ) L

Slide 41

Slide 41

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

phoneNumber . isDigitsOnly () L

Slide 42

Slide 42

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

phoneNumber .

Slide 43

Slide 43

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

phoneNumber .

Slide 44

Slide 44

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

phoneNumber . is

Slide 45

Slide 45

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z

val onlyDigits

phoneNumber . is

Slide 46

Slide 46

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z val onlyDigits

phoneNumber . isDigitsOnly () L

Slide 47

Slide 47

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

Slide 48

Slide 48

Slide 49

Slide 49

core-ktx Android KTX

Slide 50

Slide 50

Android KTX core-ktx Android framework

Slide 51

Slide 51

Android KTX Android framework support-compat core-ktx

Slide 52

Slide 52

Android KTX Android framework core core-ktx

Slide 53

Slide 53

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

Slide 54

Slide 54

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

Slide 55

Slide 55

@RequiresApi ( 26 )

operator

fun

Color . plus ( c :

Color ):

Color

{

val s

if

( colorSpace

!= c . colorSpace ) c . convert ( colorSpace )

else c

val src

s . components

val dst

components

var sa

s . alpha ()

// Destination alpha pre-composited

var da

alpha ()

( 1.0f

sa )

// Index of the alpha component

val ai

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 )

}

Slide 56

Slide 56

@RequiresApi ( 26 )

operator

fun

Color . plus ( c :

Color ):

Color

{

val s

if

( colorSpace

!= c . colorSpace ) c . convert ( colorSpace )

else c

val src

s . components

val dst

components

var sa

s . alpha ()

// Destination alpha pre-composited

var da

alpha ()

( 1.0f

sa )

// Index of the alpha component

val ai

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 )

}

Slide 57

Slide 57

@RequiresApi ( 26 )

operator

fun

Color . plus ( c :

Color ):

Color

{

val s

if

( colorSpace

!= c . colorSpace ) c . convert ( colorSpace )

else c

val src

s . components

val dst

components

var sa

s . alpha ()

// Destination alpha pre-composited

var da

alpha ()

( 1.0f

sa )

// Index of the alpha component

val ai

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 )

}

Slide 58

Slide 58

public

final

class

ColorUtils

{

} Z

Slide 59

Slide 59

public

final

class

ColorUtils

{

@ColorInt

public

static

int compositeColors (

@ColorInt

int foreground ,

@ColorInt

int background )

{

// …

} X

} Z

Slide 60

Slide 60

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

Slide 61

Slide 61

@RequiresApi ( 26 )

operator

fun

Color . plus ( c :

Color ):

Color

{

val s

if

( colorSpace

!= c . colorSpace ) c . convert ( colorSpace )

else c

val src

s . components

val dst

components

var sa

s . alpha ()

// Destination alpha pre-composited

var da

alpha ()

( 1.0f

sa )

// Index of the alpha component

val ai

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 )

}

Slide 62

Slide 62

@RequiresApi ( 26 )

inline operator

fun

Color . plus ( c :

Color ):

Color

=

ColorUtils . compositeColors ( c ,

this )

Slide 63

Slide 63

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

Slide 64

Slide 64

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

Slide 65

Slide 65

KTX Principles

Slide 66

Slide 66

KTX Principles Adapt existing functionality and redirect features upstream

Slide 67

Slide 67

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

Slide 68

Slide 68

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

Slide 69

Slide 69

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

Slide 70

Slide 70

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 )

}

Slide 71

Slide 71

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…

}

Slide 72

Slide 72

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…

}

Slide 73

Slide 73

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…

}

Slide 74

Slide 74

KTX Principles Adapt existing functionality and redirect features upstream

Slide 75

Slide 75

KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive

Slide 76

Slide 76

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

Slide 77

Slide 77

inline

fun

< reified T

Context . systemService ()

=

ContextCompat . getSystemService ( this , T :: class . java )

// In an Activity…

val notifications

systemService < NotificationManager

() H

Slide 78

Slide 78

inline

fun

View . updatePadding (

left

:

Int

=

paddingLeft ,

top

:

Int

=

paddingTop ,

right

:

Int

=

paddingRight ,

bottom

:

Int

=

paddingBottom

)

{

setPadding

( left , top , right , bottom )

} A

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 79

Slide 79

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…

Slide 80

Slide 80

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this ) Z val onlyDigits

phoneNumber . isDigitsOnly () L

Slide 81

Slide 81

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…

}

Slide 82

Slide 82

KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive

Slide 83

Slide 83

KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin

Slide 84

Slide 84

view . setOnClickListener {

// React to click…

} Z

Slide 85

Slide 85

fun

View . click ( listener :

( View )

->

Unit )

{

setOnClickListener

( listener )

} Y

view . setOnClickListener { P

// React to click…

} Z

Slide 86

Slide 86

fun

View . click ( listener :

( View )

->

Unit )

{

setOnClickListener

( listener )

} Y

view . setOnClickListener { P

// React to click…

} Z

c

Slide 87

Slide 87

fun

View . click ( listener :

( View )

->

Unit )

{

setOnClickListener

( listener )

} Y

view . click

{ P

// React to click…

} Z C

Slide 88

Slide 88

view . click

{ P

// React to click…

} Z view . setOnClickListener {

// React to click…

}

Slide 89

Slide 89

KTX Principles Adapt existing functionality and redirect features upstream Default to inline unless code size or allocation is prohibitive Leverage features unique to Kotlin

Slide 90

Slide 90

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

Slide 91

Slide 91

if

( Build . VERSION . SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 92

Slide 92

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

Slide 93

Slide 93

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

Slide 94

Slide 94

inline

fun onApi ( level :

Int , body :

()

->

Unit )

{

if

( Build . VERSION . SDK_INT

= level )

{

    body

()

} Z

} Q

onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 95

Slide 95

onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 96

Slide 96

onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z if

( Build . VERSION . SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 97

Slide 97

if

( SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 98

Slide 98

if

( SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 99

Slide 99

if

( SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z else { // Something …

}

onApi ( 19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z

Slide 100

Slide 100

if

( SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z else { // Something …

} L onApi ( 19 ) F { A

TransitionManager . beginDelayedTransition ( viewGroup )

} ,

Slide 101

Slide 101

if

( SDK_INT

=

19 )

{

TransitionManager . beginDelayedTransition ( viewGroup )

} Z else { // Something …

} L onApi ( 19 ,

{ A

TransitionManager . beginDelayedTransition ( viewGroup )

}, { T

// Something

}) F

Slide 102

Slide 102

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

Slide 103

Slide 103

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

Slide 104

Slide 104

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

Slide 105

Slide 105

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

Slide 106

Slide 106

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

Slide 107

Slide 107

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

Slide 108

Slide 108

supportFragmentManager . beginTransaction ()

. replace ( android . R . id . content , userFragment )

. commit ()

Slide 109

Slide 109

inline

fun

FragmentManager . transaction (

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

transaction

. commit ()

} supportFragmentManager . beginTransaction ()

. replace ( android . R . id . content , userFragment )

. commit ()

Slide 110

Slide 110

inline

fun

FragmentManager . transaction (

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

transaction

. commit ()

} A

supportFragmentManager . beginTransaction ()

. replace ( android . R . id . content , userFragment )

t

. commit ()

Slide 111

Slide 111

inline

fun

FragmentManager . transaction (

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

transaction

. commit ()

} A

supportFragmentManager . transaction {

replace

( android . R . id . content , userFragment )

} Z

T

Slide 112

Slide 112

inline

fun

FragmentManager . transaction (

allowStateLoss

:

Boolean

=

false

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

if

( allowStateLoss ) transaction . commitAllowingStateLoss ()

else transaction . commit ()

} A

supportFragmentManager . transaction {

replace

( android . R . id . content , userFragment )

} Z

Slide 113

Slide 113

inline

fun

FragmentManager . transaction (

allowStateLoss

:

Boolean

=

false

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

if

( allowStateLoss ) transaction . commitAllowingStateLoss ()

else transaction . commit ()

} A

supportFragmentManager . transaction { G

replace

( android . R . id . content , userFragment )

} Z

Slide 114

Slide 114

inline

fun

FragmentManager . transaction (

allowStateLoss

:

Boolean

=

false ,

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

if

( allowStateLoss ) transaction . commitAllowingStateLoss ()

else transaction . commit ()

} A

supportFragmentManager . transaction ( allowStateLoss

=

true )

{ G

replace

( android . R . id . content , userFragment )

} Z

Slide 115

Slide 115

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

Slide 116

Slide 116

inline

fun

FragmentManager . transaction (

allowStateLoss

:

Boolean

=

false ,

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

if

( allowStateLoss ) transaction . commitAllowingStateLoss ()

else transaction . commit ()

} A

supportFragmentManager . transaction ( allowStateLoss

=

true )

{ G

replace

( android . R . id . content , userFragment )

} Z

Slide 117

Slide 117

inline

fun

FragmentManager . transaction (

now

:

Boolean

=

false ,

allowStateLoss

:

Boolean

=

false ,

body

:

FragmentTransaction .()

->

Unit

)

{

val transaction

beginTransaction ()

transaction

. body ()

if

( now )

{

if

( allowStateLoss ) transaction . commitNowAllowingStateLoss ()

else transaction . commitNow ()

}

else

{

if

( allowStateLoss ) transaction . commitAllowingStateLoss ()

else transaction . commit ()

}

} A

Slide 118

Slide 118

Slide 119

Slide 119

Slide 120

Slide 120

Slide 121

Slide 121

Slide 122

Slide 122

Building Kotlin-friendly libraries

Slide 123

Slide 123

Building Kotlin-friendly libraries • Port public API or entire library to Kotlin

Slide 124

Slide 124

Building Kotlin-friendly libraries • Port public API or entire library to Kotlin

• Ship sibling artifact with Kotlin extensions

Slide 125

Slide 125

Building Kotlin-friendly libraries • Port public API or entire library to Kotlin

• Ship sibling artifact with Kotlin extensions

• ???

Slide 126

Slide 126

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 127

Slide 127

class

TextUtils

{

static

boolean isDigitsOnly ( CharSequence str )

{

int len

str . length ();

// …

} Y

} Z

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 128

Slide 128

class

TextUtils

{

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 129

Slide 129

class

TextUtils

{

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 130

Slide 130

class

TextUtils

{

@ExtensionFunction

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 131

Slide 131

class

TextUtils

{

@ExtensionFunction

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z

inline

fun

CharSequence . isDigitsOnly ()

=

TextUtils . isDigitsOnly ( this )

val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 132

Slide 132

class

TextUtils

{

@ExtensionFunction

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 133

Slide 133

class

TextUtils

{

@ExtensionFunction

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z val onlyDigits

phoneNumber . isDigitsOnly ()

Slide 134

Slide 134

class

TextUtils

{

@ExtensionFunction

static

boolean isDigitsOnly ( @NonNull

CharSequence str )

{

int len

str . length ();

// …

} Y

} Z val onlyDigits

phoneNumber . isDigitsOnly () // in the bytecode we get val

onlyDigits

TextUtils . isDigitsOnly ( phoneNumber )

Slide 135

Slide 135

inline

fun

View . updatePadding (

left

:

Int

=

paddingLeft ,

top

:

Int

=

paddingTop ,

right

:

Int

=

paddingRight ,

bottom

:

Int

=

paddingBottom

)

{

setPadding

( left , top , right , bottom )

} A

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 136

Slide 136

inline

fun

View . updatePadding (

left

:

Int

=

paddingLeft ,

top

:

Int

=

paddingTop ,

right

:

Int

=

paddingRight ,

bottom

:

Int

=

paddingBottom

)

{

setPadding

( left , top , right , bottom )

} A

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 137

Slide 137

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

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 138

Slide 138

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

Slide 139

Slide 139

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

Slide 140

Slide 140

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

avatarView. updatePadding ( left

10 , right

10 ) R

Slide 141

Slide 141

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

avatarView.setPadding ( left

10 , right

10 ) R

update

Slide 142

Slide 142

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

avatarView.setPadding ( left

10 , right

10 ) R // in bytecode we get avatarView . setPadding (

10 , avatarView . paddingTop , 10 , avatarView . paddingBottom )

update

Slide 143

Slide 143

KEEP-110

Slide 144

Slide 144

KEEP-110 • @ExtensionFunction / @ExtensionProperty — Turn a static method with at least one argument into an extension function or an extension property.

Slide 145

Slide 145

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.

Slide 146

Slide 146

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.

Slide 147

Slide 147

Building Kotlin-friendly libraries • Port public API or entire library to Kotlin

• Ship sibling artifact with Kotlin extensions

• ???

Slide 148

Slide 148

Building Kotlin-friendly libraries • Port public API or entire library to Kotlin

• Ship sibling artifact with Kotlin extensions

• KEEP-110 annotations

Slide 149

Slide 149

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

Slide 150

Slide 150

Slide 151

Slide 151

Slide 152

Slide 152

Slide 153

Slide 153

Slide 154

Slide 154

https://github.com/Kotlin/KEEP/issues/110

Slide 155

Slide 155

Jake Wharton Thank you

@JakeWharton