SlideShare a Scribd company logo
From Java to Kotlin beyond
Alt+Shift+Cmd+K
Fabio Collini
@fabioCollini
linkedin.com/in/fabiocollini
github.com/fabioCollini
medium.com/@fabioCollini
codingjam.it
Android programmazione avanzata
Android Developers Italia
Ego slide
Kotlin can be configured in one click
A Java class can be converted easily
ok, now what?
COLLE
CTIONS
ASYNC
CODE
DELE
GATES
Agenda
COMPANION
OBJECTS
COLLE
CTIONS
for (Person person : people) {
City city = person.getAddress().getCity();
if (city.getRegion().equals("Tuscany")) {
cities.add(city.getName() + " (" + city.getCode() + ")");
}1
}2
System.out.println(b.toString());
List<Person> people = Arrays.asList(...);
StringBuilder b = new StringBuilder();
for (String s : cities) {
if (b.length() > 0) {
b.append(", ");
}3
b.append(s);
}4
Set<String> cities = new TreeSet<>();
val people = listOf(...)
val s = people
.map { it.address.city }
.filter { it.region == "Tuscany" }
.distinct()
.sortedBy { it.name }
.joinToString { "${it.name} (${it.code})" }
println(s)
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
String s = Stream.of(people)
.map(it -> it.getAddress().getCity())
.filter(it -> it.getRegion().equals("Tuscany"))
.distinct()
.sortBy(City::getName)
.map(it -> it.getName() + " (" + it.getCode() + ")")
.collect(Collectors.joining(", "));
System.out.println(s);
val people = listOf(...)
val s = people
.map { it.address.city }
.filter { it.region == "Tuscany" }
.distinct()
.sortedBy { it.name }
.joinToString { "${it.name} (${it.code})" }
println(s)
val people = listOf(...)
val s = people
.asSequence()
.map { it.address.city }
.filter { it.region == "Tuscany" }
.map { "${it.name} (${it.code})" }
.first()
println(s)
val youngest = people.minBy { it.age }
val peopleByCity: Map<City, List<Person>> =
people.groupBy { it.address.city }
val all: Boolean = people.all {
it.address.city.name == "Florence"
}1
val any: Boolean = people.any {
it.address.city.name == "Florence"
}2
val (adults: List<Person>, minors: List<Person>) =
people.partition { it.age >= 18 }
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
interface List<out E> : Collection<E> {
//...
operator fun get(index: Int): E
//...
}
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val mutableList: MutableList<Int> = mutableListOf(10, 20, 30)
mutableList[1] = 21
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val mutableList: MutableList<Int> = mutableListOf(10, 20, 30)
mutableList[1] = 21
interface MutableList<E> : List<E>, MutableCollection<E> {
//...
operator fun set(index: Int, element: E): E
//...
}
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val mutableList: MutableList<Int> = mutableListOf(10, 20, 30)
mutableList[1] = 21
val map = mapOf(1 to "ABC", 2 to "DEF")
infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val mutableList: MutableList<Int> = mutableListOf(10, 20, 30)
mutableList[1] = 21
val map = mapOf(1 to "ABC", 2 to "DEF")
val abc = map[1]
interface Map<K, out V> {
//...
operator fun get(key: K): V?
//...
}
val readOnlyList: List<Int> = listOf(10, 20, 30)
val secondElement = readOnlyList[1]
val mutableList: MutableList<Int> = mutableListOf(10, 20, 30)
mutableList[1] = 21
val map = mapOf(1 to "ABC", 2 to "DEF")
val abc = map[1]
val mutableMap = mutableMapOf(1 to "ABC", 2 to "DEF")
mutableMap[3] = "XYZ"
inline operator fun <K, V> MutableMap<K, V>.set(
key: K, value: V): Unit {
put(key, value)
}
val otherList = (mutableList - readOnlyList) + mutableMap.keys
public operator fun <T> Iterable<T>.minus(
elements: Iterable<T>): List<T> {
//...
}
public operator fun <T> Collection<T>.plus(
elements: Iterable<T>): List<T> {
//...
}
COMPANION
OBJECTS
private const val MY_PARAM = "my_param"
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object {
fun newInstance(param: String): MyFragment {
return MyFragment().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}9
}0
public class MyFragment extends Fragment {
public static final Companion Companion = new Companion();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String myStringParam = getParam();
//...
}9
public String getParam() {
return getArguments().getString("my_param");
}8
public static final class Companion {
public final MyFragment newInstance(String param) {
MyFragment fragment = new MyFragment();
Bundle bundle = BundleKt.bundleOf(
new Pair[] {
TuplesKt.to("my_param", param)
}1
);
fragment.setArguments(bundle);
return fragment;
}2
}3
}4
private const val MY_PARAM = "my_param"
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object {
fun newInstance(param: String): MyFragment {
return MyFragment().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}9
}0
private const val MY_PARAM = "my_param"
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object {
@JvmStatic
fun newInstance(param: String): MyFragment {
return MyFragment().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}9
}0
public class MyFragment extends Fragment {
public static final Companion Companion = new Companion();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String myStringParam = getParam();
//...
}9
public String getParam() {
return getArguments().getString("my_param");
}8
public static MyFragment newInstance(String param) {
return Companion.newInstance(param);
}x
public static final class Companion {
public final MyFragment newInstance(String param) {
MyFragment fragment = new MyFragment();
Bundle bundle = BundleKt.bundleOf(
new Pair[] {
TuplesKt.to("my_param", param)
}1
);
fragment.setArguments(bundle);
return fragment;
}2
}3
}4
private const val MY_PARAM = "my_param"
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object {
fun newInstance(param: String): MyFragment {
return MyFragment().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}9
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object : FragmentCreator<String>(::MyFragment) {2
fun newInstance(param: String): MyFragment {
return MyFragment().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}9
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object : FragmentCreator<String>(::MyFragment)
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
val param
get() = arguments!!.getString(MY_PARAM)
companion object : FragmentCreator<String>(::MyFragment)
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val param
get() = arguments!!.get(MY_PARAM) as T
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
companion object : FragmentCreator<String>(::MyFragment)
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val Fragment.param
get() = arguments!!.get(MY_PARAM) as T
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
companion object : FragmentCreator<String>(::MyFragment)
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val Fragment.param
get() = arguments!!.get(MY_PARAM) as T
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
companion object : FragmentCreator<String>(::MyFragment)
}0
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val Fragment.param
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}
}1
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
companion object : FragmentCreator<String>(::MyFragment)
}0
class MyFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val myStringParam = param
//...
}5
companion object : FragmentCreator<String>(::MyFragment)
}0
val fragment = MyFragment.newInstance("ABC")
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val Fragment.param: T
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}
}1
fun bundleOf(vararg pairs: Pair<String, Any?>) = Bundle(pairs.size).apply {
for ((key, value) in pairs) {
when (value) {
null -> putString(key, null) // Any nullable type will suffice.
// Scalars
is Boolean -> putBoolean(key, value)
is Byte -> putByte(key, value)
is Char -> putChar(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Short -> putShort(key, value)
// References
is Bundle -> putBundle(key, value)
is CharSequence -> putCharSequence(key, value)
is Parcelable -> putParcelable(key, value)
// Scalar arrays
is BooleanArray -> putBooleanArray(key, value)
is ByteArray -> putByteArray(key, value)
is CharArray -> putCharArray(key, value)
is DoubleArray -> putDoubleArray(key, value)
is FloatArray -> putFloatArray(key, value)
is IntArray -> putIntArray(key, value)
is LongArray -> putLongArray(key, value)
is ShortArray -> putShortArray(key, value)
// Reference arrays
is Array<*> -> {
val componentType = value::class.java.componentType
@Suppress("UNCHECKED_CAST") // Checked by reflection.
when {
Parcelable::class.java.isAssignableFrom(componentType) -> {
putParcelableArray(key, value as Array<Parcelable>)
}
String::class.java.isAssignableFrom(componentType) -> {
putStringArray(key, value as Array<String>)
}
CharSequence::class.java.isAssignableFrom(componentType) -> {
putCharSequenceArray(key, value as Array<CharSequence>)
}
Serializable::class.java.isAssignableFrom(componentType) -> {
putSerializable(key, value)
}
else -> {
val valueType = componentType.canonicalName
throw IllegalArgumentException(
"Illegal value array type $valueType for key "$key"")
}5
}6
}7
// Last resort. Also we must check this after Array<*> as all arrays are serializable.
is Serializable -> putSerializable(key, value)
else -> {
if (Build.VERSION.SDK_INT >= 18 && value is Binder) {
putBinder(key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is Size) {
putSize(key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) {
putSizeF(key, value)
} else {
val valueType = value.javaClass.canonicalName
throw IllegalArgumentException("Illegal value type $valueType for key "$key"")
}1
}2
}3
}4
}5
fun bundleOf(vararg pairs: Pair<String, Any?>) = Bundle(pairs.size).apply {
for ((key, value) in pairs) {
when (value) {
null -> putString(key, null) // Any nullable type will suffice.
// Scalars
is Boolean -> putBoolean(key, value)
is Byte -> putByte(key, value)
is Char -> putChar(key, value)
is Double -> putDouble(key, value)
is Float -> putFloat(key, value)
is Int -> putInt(key, value)
is Long -> putLong(key, value)
is Short -> putShort(key, value)
// References
is Bundle -> putBundle(key, value)
is CharSequence -> putCharSequence(key, value)
is Parcelable -> putParcelable(key, value)
// Scalar arrays
is BooleanArray -> putBooleanArray(key, value)
is ByteArray -> putByteArray(key, value)
is CharArray -> putCharArray(key, value)
is DoubleArray -> putDoubleArray(key, value)
is FloatArray -> putFloatArray(key, value)
is IntArray -> putIntArray(key, value)
is LongArray -> putLongArray(key, value)
}
Serializable::class.java.isAssignableFrom(componentType) -> {
putSerializable(key, value)
}
else -> {
val valueType = componentType.canonicalName
throw IllegalArgumentException(
"Illegal value array type $valueType for key "$key"")
}5
}6
}7
// Last resort. Also we must check this after Array<*> as all arrays are serializable.
is Serializable -> putSerializable(key, value)
else -> {
if (Build.VERSION.SDK_INT >= 18 && value is Binder) {
putBinder(key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is Size) {
putSize(key, value)
} else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) {
putSizeF(key, value)
} else {
val valueType = value.javaClass.canonicalName
throw IllegalArgumentException("Illegal value type $valueType for key "$key"")
}1
}2
}3
}4
}5
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
fun newInstance(param: T) : Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
val Fragment.param: T
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}2
}1
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
val Fragment.param: T
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}2
}1
fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment {
return factory().apply {
arguments = bundleOf(MY_PARAM to param)
}7
}8
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
val Fragment.param: T
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}2
}1
fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment {
return factory().apply {4
arguments = Bundle().apply {5
putParcelable(MY_PARAM, param)
}6
}7
}8
private const val MY_PARAM = "my_param"
open class FragmentCreator<T>(
val factory: () -> Fragment
) {
val Fragment.param: T
get() = arguments!!.get(MY_PARAM) as T
fun param(fragment: Fragment): T {
return fragment.arguments!!.get(MY_PARAM) as T
}2
}1
fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment {
return factory().apply {4
arguments = Bundle().apply {5
putParcelable(MY_PARAM, param)
}6
}7
}8
fun FragmentCreator<String>.newInstance(param: String): Fragment {
return factory().apply {
arguments = Bundle().apply {
putString(MY_PARAM, param)
}
}
}
ASYNC
CODE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myTextView = findViewById<TextView>(R.id.text)
myTextView.text = "Loading..."
Thread.sleep(2000)
myTextView.text = "Loading something else..."
Thread.sleep(2000)
myTextView.text = "Done"
}_
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myTextView = findViewById<TextView>(R.id.text)
myTextView.text = "Loading..."
Thread.sleep(2000)
myTextView.text = "Loading something else..."
Thread.sleep(2000)
myTextView.text = "Done"
}_
/**
* Delays coroutine for a given time without blocking
* a thread and resumes it after a specified time.
* ...
*/
suspend fun delay(time: Long, unit: TimeUnit = MILLISECONDS) {
//...
}
suspend
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myTextView = findViewById<TextView>(R.id.text)
launch(UI) {
myTextView.text = "Loading..."
delay(2000)
myTextView.text = "Loading something else..."
delay(2000)
myTextView.text = "Done"
}async
}end
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myTextView = findViewById<TextView>(R.id.text)
launch(UI) {
myTextView.text = "Loading..."
delay(2000)
myTextView.text = "Loading something else..."
delay(2000)
myTextView.text = "Done"
}async
}end
class MyService {
fun loadData(): String {
//...
return slowMethod()
}1
private fun slowMethod(): String {
//...
}2
}3
class MyService {
suspend fun loadData(): String {
return withContext(CommonPool) {
//...
slowMethod()
}5
}1
private fun slowMethod(): String {
//...
}2
}3
class MyViewModel(
private val service: MyService
) : ViewModel() {
private val job = Job()
fun load() {
launch(CommonPool + job) {
try {
val data = service.loadData()
updateUi(data)
} catch (e: Exception) {
updateUi(e.message)
}1
}2
}3
private suspend fun updateUi(s: String?) {
withContext(UI) {
//...
}4
}5
override fun onCleared() {
job.cancel()
}6
}7
class MyViewModel(
private val service: MyService
) : ViewModel() {
private val job = Job()
fun load() {
launch(CommonPool + job) {
try {
val data = service.loadData()
updateUi(data)
} catch (e: Exception) {
updateUi(e.message)
}1
}2
}3
private suspend fun updateUi(s: String?) {
withContext(UI) {
//...
}4
}5
override fun onCleared() {
job.cancel()
}6
}7
class MyViewModel(
private val service: MyService
) : ViewModel() {
private val job = Job()
fun load() {
launch(CommonPool + job) {
try {
val data = service.loadData()
updateUi(data)
} catch (e: Exception) {
updateUi(e.message)
}1
}2
}3
private suspend fun updateUi(s: String?) {
withContext(UI) {
//...
}4
}5
override fun onCleared() {
job.cancel()
}6
}7
class MyViewModel(
private val service: MyService
) : ViewModel() {
private val job = Job()
fun load() {
launch(CommonPool + job) {
try {
val data = service.loadData()
updateUi(data)
} catch (e: Exception) {
updateUi(e.message)
}1
}2
}3
private suspend fun updateUi(s: String?) {
withContext(UI) {
//...
}4
}5
override fun onCleared() {
job.cancel()
}6
}7
class MyViewModel(
private val service: MyService
) : ViewModel() {
private val job = Job()
fun load() {
launch(CommonPool + job) {
try {
val data = service.loadData()
updateUi(data)
} catch (e: Exception) {
updateUi(e.message)
}1
}2
}3
private suspend fun updateUi(s: String?) {
withContext(UI) {
//...
}4
}5
override fun onCleared() {
job.cancel()
}6
}7
interface MyService {
@GET("login")
fun login(): Deferred<String>
@GET("data")
fun loadData(@Query(“token") token: String): Deferred<Data>
}A
interface MyService {
@GET("login")
fun login(): Deferred<String>
@GET("data")
fun loadData(@Query(“token") token: String): Deferred<Data>
}A
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
showInUi(data)
} catch (e: Exception) {
showError(e)
}__
}___
service.login()
.flatMap { service.loadData(it) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data -> showInUi(data) },
{ showError(it) }
)end
RxJavaCoroutines
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
showInUi(data)
} catch (e: Exception) {
showError(e)
}__
}___
RxJava
Coroutines
OR
RxJava
Coroutines
AND
RxJava Coroutines->
RxJavaCoroutines ->
rxCompletable, rxMaybe, rxSingle, rxObservable, rxFlowable
CompletableSource.await, MaybeSource.await, MaybeSource.awaitOrDefault,
MaybeSource.openSubscription, SingleSource.await,
ObservableSource.awaitFirst, ObservableSource.awaitFirstOrDefault,
ObservableSource.awaitFirstOrElse, ObservableSource.awaitFirstOrNull,
ObservableSource.awaitLast, ObservableSource.awaitSingle,
ObservableSource.openSubscription, ObservableSource.iterator
github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx2
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
showInUi(data)1
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
showInUi(data)1
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
val otherData = service.loadOtherData(token).await()
showInUi(data, otherData)1
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
val token = service.login().await()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())1
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
val token = service.login().await()
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
withTimeout(10, SECONDS) {
val token = service.login().await()
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
}B
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
withTimeout(10, SECONDS) {
val token = retry(3) {
service.login().await()
}T
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
}B
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
withTimeout(10, SECONDS) {
val token = retry(3) {
service.login().await()
}T
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
}B
} catch (e: Exception) {
showError(e)
}__
}___
suspend fun <T> retry(times: Int, f: suspend () -> T): T {
repeat(times - 1) {
try {
return f()
} catch (ignored: Exception) {
}
}
return f()
}
launch(CommonPool) {
try {
withTimeout(10, SECONDS) {
val token = exponentialBackoff(3) {
service.login().await()
}T
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
}B
} catch (e: Exception) {
showError(e)
}__
}___
launch(CommonPool) {
try {
withTimeout(10, SECONDS) {
val token = exponentialBackoff(3) {
service.login().await()
}T
updateProgress()
val data = service.loadData(token)
val otherData = service.loadOtherData(token)
showInUi(data.await(), otherData.await())
}B
} catch (e: Exception) {
showError(e)
}__
}___
suspend fun <T> exponentialBackoff(times: Int, f: suspend () -> T): T {
var currentDelay = 100 + Random().nextInt(100)
repeat(times - 1) {
try {
return f()
} catch (e: Exception) {
}
delay(currentDelay)
currentDelay *= 2
}
return f()
}
launch
executes a task on a coroutine context
an uncaught exception stops the app
used to start a computation
Deferred
await returns the result or throws an exception
can be used to execute something in parallel
can be created using async
withContext
suspending method
changes the execution thread
useful to force the execution of a method on a thread
My 2 cents
Suspending methods are easier to
use than RxJava Singles
Observables/Flowables are the best
abstraction for a stream of data
DELE
GATES
class TokenHolder {0
var token = ""
}1
class TokenHolder {0
var token = ""
}1
public class TokenHolder {
private String token = "";
public String getToken() {
return this.token;
}1
public void setToken(String token) {
this.token = token;
}2
}3
class TokenHolder {0
var token = ""
}1
class TokenHolder(private val prefs: SharedPreferences) {0
var token = ""
}1
class TokenHolder(private val prefs: SharedPreferences) {
var token
get() = prefs.getString("token", "")
set(value) = prefs.edit().putString("token", value).apply()
}1
class TokenHolder(private val prefs: SharedPreferences) {
var token
get() = prefs.getString("token", "")
set(value) = prefs.edit().putString("token", value).apply()
}1
public class TokenHolder {
private final SharedPreferences prefs;
public TokenHolder(SharedPreferences prefs) {
this.prefs = prefs;
}1
public final String getToken() {
return this.prefs.getString("token", "");
}2
public final void setToken(String value) {
this.prefs.edit().putString("token", value).apply();
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token
get() = prefs.getString("token", "")
set(value) = prefs.edit().putString("token", value).apply()
}1
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
fun SharedPreferences.string(): ReadWriteProperty<Any, String> {
return object : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return getString(property.name, "")
}2
override fun setValue(thisRef: Any, property: KProperty<*>,
value: String) {
edit().putString(property.name, value).apply()
}3
}4
}5
fun SharedPreferences.string(
defaultValue: String = ""
): ReadWriteProperty<Any, String> {
return object : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return getString(property.name, defaultValue)
}2
override fun setValue(thisRef: Any, property: KProperty<*>,
value: String) {
edit().putString(property.name, value).apply()
}3
}4
}5
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
fun SharedPreferences.string(
defaultValue: String = "",
key: String? = null
): ReadWriteProperty<Any, String> {
return object : ReadWriteProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return getString(key ?: property.name, defaultValue)
}2
override fun setValue(thisRef: Any, property: KProperty<*>,
value: String) {
edit().putString(key ?: property.name, value).apply()
}3
}4
}5
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
public class TokenHolder {
static final KProperty delegatedProperty = //..
private final ReadWriteProperty token$delegate;
public TokenHolder(SharedPreferences prefs) {
this.token$delegate = PrefsKt.string(prefs, null, null);
}1
public final String getToken() {
return (String)token$delegate.getValue(this, delegatedProperty);
}2
public final void setToken(String var1) {
token$delegate.setValue(this, delegatedProperty, var1);
}3
}4
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string()
}1
tokenHolder.token += "ABC"
prefs.edit().putString(
"token",
prefs.getString("token", "") + "ABC"
).apply()
Wrapping up
Alt+Shift+Cmd+K is just the beginning
functional code is natural in Kotlin
code can be simplified using
companion objects, coroutines and
delegates
Links
Demo Project
github.com/fabioCollini/ArchitectureComponentsDemo
Libraries
Lightweight Stream github.com/aNNiMON/Lightweight-Stream-API
Guides and posts
Guide to kotlinx.coroutines by example
github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md
Async code using Kotlin Coroutines
proandroiddev.com/async-code-using-kotlin-coroutines-233d201099ff
Kotlin delegates in Android development part 1
hackernoon.com/kotlin-delegates-in-android-development-part-1-50346cf4aed7
Kotlin delegates in Android development part 2
proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438
THANKS
FOR YOUR
ATTENTION
QUESTIONS?
Android Developers Italia
androiddevs.it
Ad

More Related Content

What's hot (20)

SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
Christian Baranowski
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
Mike Fogus
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
진성 오
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
André Faria Gomes
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
Mike Fogus
 
RxSwift 시작하기
RxSwift 시작하기RxSwift 시작하기
RxSwift 시작하기
Suyeol Jeon
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
Emil Vladev
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
Husain Dalal
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
Iran Entrepreneurship Association
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
Eleanor McHugh
 
The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181
Mahmoud Samir Fayed
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragment
Chiwon Song
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
Chiwon Song
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
StackMob Inc
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
Mike Fogus
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
Chiwon Song
 
Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)
진성 오
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby Hackers
Eleanor McHugh
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
Tsuyoshi Yamamoto
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
Mike Fogus
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
진성 오
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
Mike Fogus
 
RxSwift 시작하기
RxSwift 시작하기RxSwift 시작하기
RxSwift 시작하기
Suyeol Jeon
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
Husain Dalal
 
Implementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 reduxImplementing virtual machines in go & c 2018 redux
Implementing virtual machines in go & c 2018 redux
Eleanor McHugh
 
The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181The Ring programming language version 1.5.2 book - Part 45 of 181
The Ring programming language version 1.5.2 book - Part 45 of 181
Mahmoud Samir Fayed
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragment
Chiwon Song
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
Chiwon Song
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
StackMob Inc
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
Mike Fogus
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
Chiwon Song
 
Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)
진성 오
 
Google Go For Ruby Hackers
Google Go For Ruby HackersGoogle Go For Ruby Hackers
Google Go For Ruby Hackers
Eleanor McHugh
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 

Similar to From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan (20)

Miracle of std lib
Miracle of std libMiracle of std lib
Miracle of std lib
Jedsada Tiwongvokul
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
tdc-globalcode
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
Shaul Rosenzwieg
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
潤一 加藤
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
Eleanor McHugh
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
iMasters
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
Franco Lombardo
 
ハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使う
bpstudy
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kirill Rozov
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
Fabio Collini
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Codemotion
 
Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
Paweł Byszewski
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
Mario Fusco
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
Matthew Tovbin
 
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
Databricks
 
つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~
kamedon39
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
PROIDEA
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
tdc-globalcode
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
Eleanor McHugh
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
iMasters
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
Franco Lombardo
 
ハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使う
bpstudy
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kirill Rozov
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
Fabio Collini
 
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Kotlin for Android Developers - Victor Kropp - Codemotion Rome 2018
Codemotion
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
Mario Fusco
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
Dmitry Sheiko
 
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
The Rule of 10,000 Spark Jobs - Learning from Exceptions and Serializing Your...
Matthew Tovbin
 
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
The Rule of 10,000 Spark Jobs: Learning From Exceptions and Serializing Your ...
Databricks
 
つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~
kamedon39
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
PROIDEA
 
What's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritageWhat's in Kotlin for us - Alexandre Greschon, MyHeritage
What's in Kotlin for us - Alexandre Greschon, MyHeritage
DroidConTLV
 
Ad

More from Fabio Collini (20)

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
Fabio Collini
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
Fabio Collini
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
Fabio Collini
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community conf
Fabio Collini
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Fabio Collini
 
Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
Fabio Collini
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
Fabio Collini
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
Fabio Collini
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
Fabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
Fabio Collini
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
Fabio Collini
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
Fabio Collini
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
Fabio Collini
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
Fabio Collini
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
Fabio Collini
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
Fabio Collini
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
Fabio Collini
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
Fabio Collini
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
Fabio Collini
 
Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
Fabio Collini
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
Fabio Collini
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
Fabio Collini
 
Kotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community confKotlin Delegates in practice - Kotlin community conf
Kotlin Delegates in practice - Kotlin community conf
Fabio Collini
 
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere StockholmKotlin delegates in practice - Kotlin Everywhere Stockholm
Kotlin delegates in practice - Kotlin Everywhere Stockholm
Fabio Collini
 
Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
Fabio Collini
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
Fabio Collini
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
Fabio Collini
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
Fabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
Fabio Collini
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
Fabio Collini
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
Fabio Collini
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
Fabio Collini
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
Fabio Collini
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
Fabio Collini
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
Fabio Collini
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
Fabio Collini
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
Fabio Collini
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
Fabio Collini
 
Ad

Recently uploaded (20)

Gojek Clone App for Multi-Service Business
Gojek Clone App for Multi-Service BusinessGojek Clone App for Multi-Service Business
Gojek Clone App for Multi-Service Business
XongoLab Technologies LLP
 
The Elixir Developer - All Things Open
The Elixir Developer - All Things OpenThe Elixir Developer - All Things Open
The Elixir Developer - All Things Open
Carlo Gilmar Padilla Santana
 
[gbgcpp] Let's get comfortable with concepts
[gbgcpp] Let's get comfortable with concepts[gbgcpp] Let's get comfortable with concepts
[gbgcpp] Let's get comfortable with concepts
Dimitrios Platis
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdfProtect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
株式会社クライム
 
From Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
From Vibe Coding to Vibe Testing - Complete PowerPoint PresentationFrom Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
From Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
Shay Ginsbourg
 
Adobe Media Encoder Crack FREE Download 2025
Adobe Media Encoder  Crack FREE Download 2025Adobe Media Encoder  Crack FREE Download 2025
Adobe Media Encoder Crack FREE Download 2025
zafranwaqar90
 
Solar-wind hybrid engery a system sustainable power
Solar-wind  hybrid engery a system sustainable powerSolar-wind  hybrid engery a system sustainable power
Solar-wind hybrid engery a system sustainable power
bhoomigowda12345
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
GDS SYSTEM | GLOBAL DISTRIBUTION SYSTEM
GDS SYSTEM | GLOBAL  DISTRIBUTION SYSTEMGDS SYSTEM | GLOBAL  DISTRIBUTION SYSTEM
GDS SYSTEM | GLOBAL DISTRIBUTION SYSTEM
philipnathen82
 
Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025
Phil Eaton
 
Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
Ranking Google
 
sequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineeringsequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineering
aashrithakondapalli8
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
AEM User Group DACH - 2025 Inaugural Meeting
AEM User Group DACH - 2025 Inaugural MeetingAEM User Group DACH - 2025 Inaugural Meeting
AEM User Group DACH - 2025 Inaugural Meeting
jennaf3
 
How to avoid IT Asset Management mistakes during implementation_PDF.pdf
How to avoid IT Asset Management mistakes during implementation_PDF.pdfHow to avoid IT Asset Management mistakes during implementation_PDF.pdf
How to avoid IT Asset Management mistakes during implementation_PDF.pdf
victordsane
 
Exchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv SoftwareExchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv Software
Shoviv Software
 
Artificial hand using embedded system.pptx
Artificial hand using embedded system.pptxArtificial hand using embedded system.pptx
Artificial hand using embedded system.pptx
bhoomigowda12345
 
[gbgcpp] Let's get comfortable with concepts
[gbgcpp] Let's get comfortable with concepts[gbgcpp] Let's get comfortable with concepts
[gbgcpp] Let's get comfortable with concepts
Dimitrios Platis
 
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.pptPassive House Canada Conference 2025 Presentation [Final]_v4.ppt
Passive House Canada Conference 2025 Presentation [Final]_v4.ppt
IES VE
 
Medical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk ScoringMedical Device Cybersecurity Threat & Risk Scoring
Medical Device Cybersecurity Threat & Risk Scoring
ICS
 
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdfProtect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
Protect HPE VM Essentials using Veeam Agents-a50012338enw.pdf
株式会社クライム
 
From Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
From Vibe Coding to Vibe Testing - Complete PowerPoint PresentationFrom Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
From Vibe Coding to Vibe Testing - Complete PowerPoint Presentation
Shay Ginsbourg
 
Adobe Media Encoder Crack FREE Download 2025
Adobe Media Encoder  Crack FREE Download 2025Adobe Media Encoder  Crack FREE Download 2025
Adobe Media Encoder Crack FREE Download 2025
zafranwaqar90
 
Solar-wind hybrid engery a system sustainable power
Solar-wind  hybrid engery a system sustainable powerSolar-wind  hybrid engery a system sustainable power
Solar-wind hybrid engery a system sustainable power
bhoomigowda12345
 
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptxThe-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
The-Future-is-Hybrid-Exploring-Azure’s-Role-in-Multi-Cloud-Strategies.pptx
james brownuae
 
GDS SYSTEM | GLOBAL DISTRIBUTION SYSTEM
GDS SYSTEM | GLOBAL  DISTRIBUTION SYSTEMGDS SYSTEM | GLOBAL  DISTRIBUTION SYSTEM
GDS SYSTEM | GLOBAL DISTRIBUTION SYSTEM
philipnathen82
 
Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025Memory Management and Leaks in Postgres from pgext.day 2025
Memory Management and Leaks in Postgres from pgext.day 2025
Phil Eaton
 
Best HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRMBest HR and Payroll Software in Bangladesh - accordHRM
Best HR and Payroll Software in Bangladesh - accordHRM
accordHRM
 
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
!%& IDM Crack with Internet Download Manager 6.42 Build 32 >
Ranking Google
 
sequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineeringsequencediagrams.pptx software Engineering
sequencediagrams.pptx software Engineering
aashrithakondapalli8
 
wAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptxwAIred_LearnWithOutAI_JCON_14052025.pptx
wAIred_LearnWithOutAI_JCON_14052025.pptx
SimonedeGijt
 
AEM User Group DACH - 2025 Inaugural Meeting
AEM User Group DACH - 2025 Inaugural MeetingAEM User Group DACH - 2025 Inaugural Meeting
AEM User Group DACH - 2025 Inaugural Meeting
jennaf3
 
How to avoid IT Asset Management mistakes during implementation_PDF.pdf
How to avoid IT Asset Management mistakes during implementation_PDF.pdfHow to avoid IT Asset Management mistakes during implementation_PDF.pdf
How to avoid IT Asset Management mistakes during implementation_PDF.pdf
victordsane
 
Exchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv SoftwareExchange Migration Tool- Shoviv Software
Exchange Migration Tool- Shoviv Software
Shoviv Software
 
Artificial hand using embedded system.pptx
Artificial hand using embedded system.pptxArtificial hand using embedded system.pptx
Artificial hand using embedded system.pptx
bhoomigowda12345
 

From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan

  • 1. From Java to Kotlin beyond Alt+Shift+Cmd+K Fabio Collini
  • 3. Kotlin can be configured in one click
  • 4. A Java class can be converted easily
  • 8. for (Person person : people) { City city = person.getAddress().getCity(); if (city.getRegion().equals("Tuscany")) { cities.add(city.getName() + " (" + city.getCode() + ")"); }1 }2 System.out.println(b.toString()); List<Person> people = Arrays.asList(...); StringBuilder b = new StringBuilder(); for (String s : cities) { if (b.length() > 0) { b.append(", "); }3 b.append(s); }4 Set<String> cities = new TreeSet<>();
  • 9. val people = listOf(...) val s = people .map { it.address.city } .filter { it.region == "Tuscany" } .distinct() .sortedBy { it.name } .joinToString { "${it.name} (${it.code})" } println(s)
  • 11. String s = Stream.of(people) .map(it -> it.getAddress().getCity()) .filter(it -> it.getRegion().equals("Tuscany")) .distinct() .sortBy(City::getName) .map(it -> it.getName() + " (" + it.getCode() + ")") .collect(Collectors.joining(", ")); System.out.println(s);
  • 12. val people = listOf(...) val s = people .map { it.address.city } .filter { it.region == "Tuscany" } .distinct() .sortedBy { it.name } .joinToString { "${it.name} (${it.code})" } println(s)
  • 13. val people = listOf(...) val s = people .asSequence() .map { it.address.city } .filter { it.region == "Tuscany" } .map { "${it.name} (${it.code})" } .first() println(s)
  • 14. val youngest = people.minBy { it.age } val peopleByCity: Map<City, List<Person>> = people.groupBy { it.address.city } val all: Boolean = people.all { it.address.city.name == "Florence" }1 val any: Boolean = people.any { it.address.city.name == "Florence" }2 val (adults: List<Person>, minors: List<Person>) = people.partition { it.age >= 18 }
  • 15. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1]
  • 16. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] interface List<out E> : Collection<E> { //... operator fun get(index: Int): E //... }
  • 17. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] val mutableList: MutableList<Int> = mutableListOf(10, 20, 30) mutableList[1] = 21
  • 18. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] val mutableList: MutableList<Int> = mutableListOf(10, 20, 30) mutableList[1] = 21 interface MutableList<E> : List<E>, MutableCollection<E> { //... operator fun set(index: Int, element: E): E //... }
  • 19. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] val mutableList: MutableList<Int> = mutableListOf(10, 20, 30) mutableList[1] = 21 val map = mapOf(1 to "ABC", 2 to "DEF") infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
  • 20. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] val mutableList: MutableList<Int> = mutableListOf(10, 20, 30) mutableList[1] = 21 val map = mapOf(1 to "ABC", 2 to "DEF") val abc = map[1] interface Map<K, out V> { //... operator fun get(key: K): V? //... }
  • 21. val readOnlyList: List<Int> = listOf(10, 20, 30) val secondElement = readOnlyList[1] val mutableList: MutableList<Int> = mutableListOf(10, 20, 30) mutableList[1] = 21 val map = mapOf(1 to "ABC", 2 to "DEF") val abc = map[1] val mutableMap = mutableMapOf(1 to "ABC", 2 to "DEF") mutableMap[3] = "XYZ" inline operator fun <K, V> MutableMap<K, V>.set( key: K, value: V): Unit { put(key, value) }
  • 22. val otherList = (mutableList - readOnlyList) + mutableMap.keys public operator fun <T> Iterable<T>.minus( elements: Iterable<T>): List<T> { //... } public operator fun <T> Collection<T>.plus( elements: Iterable<T>): List<T> { //... }
  • 24. private const val MY_PARAM = "my_param" class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object { fun newInstance(param: String): MyFragment { return MyFragment().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }9 }0
  • 25. public class MyFragment extends Fragment { public static final Companion Companion = new Companion(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String myStringParam = getParam(); //... }9 public String getParam() { return getArguments().getString("my_param"); }8 public static final class Companion { public final MyFragment newInstance(String param) { MyFragment fragment = new MyFragment(); Bundle bundle = BundleKt.bundleOf( new Pair[] { TuplesKt.to("my_param", param) }1 ); fragment.setArguments(bundle); return fragment; }2 }3 }4 private const val MY_PARAM = "my_param" class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object { fun newInstance(param: String): MyFragment { return MyFragment().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }9 }0
  • 26. private const val MY_PARAM = "my_param" class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object { @JvmStatic fun newInstance(param: String): MyFragment { return MyFragment().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }9 }0 public class MyFragment extends Fragment { public static final Companion Companion = new Companion(); public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String myStringParam = getParam(); //... }9 public String getParam() { return getArguments().getString("my_param"); }8 public static MyFragment newInstance(String param) { return Companion.newInstance(param); }x public static final class Companion { public final MyFragment newInstance(String param) { MyFragment fragment = new MyFragment(); Bundle bundle = BundleKt.bundleOf( new Pair[] { TuplesKt.to("my_param", param) }1 ); fragment.setArguments(bundle); return fragment; }2 }3 }4
  • 27. private const val MY_PARAM = "my_param" class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object { fun newInstance(param: String): MyFragment { return MyFragment().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }9 }0
  • 28. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object : FragmentCreator<String>(::MyFragment) {2 fun newInstance(param: String): MyFragment { return MyFragment().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }9 }0
  • 29. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object : FragmentCreator<String>(::MyFragment) }0
  • 30. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 val param get() = arguments!!.getString(MY_PARAM) companion object : FragmentCreator<String>(::MyFragment) }0
  • 31. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val param get() = arguments!!.get(MY_PARAM) as T }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 companion object : FragmentCreator<String>(::MyFragment) }0
  • 32. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val Fragment.param get() = arguments!!.get(MY_PARAM) as T }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 companion object : FragmentCreator<String>(::MyFragment) }0
  • 33. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val Fragment.param get() = arguments!!.get(MY_PARAM) as T }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 companion object : FragmentCreator<String>(::MyFragment) }0
  • 34. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val Fragment.param get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T } }1 class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 companion object : FragmentCreator<String>(::MyFragment) }0
  • 35. class MyFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val myStringParam = param //... }5 companion object : FragmentCreator<String>(::MyFragment) }0 val fragment = MyFragment.newInstance("ABC")
  • 36. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val Fragment.param: T get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T } }1
  • 37. fun bundleOf(vararg pairs: Pair<String, Any?>) = Bundle(pairs.size).apply { for ((key, value) in pairs) { when (value) { null -> putString(key, null) // Any nullable type will suffice. // Scalars is Boolean -> putBoolean(key, value) is Byte -> putByte(key, value) is Char -> putChar(key, value) is Double -> putDouble(key, value) is Float -> putFloat(key, value) is Int -> putInt(key, value) is Long -> putLong(key, value) is Short -> putShort(key, value) // References is Bundle -> putBundle(key, value) is CharSequence -> putCharSequence(key, value) is Parcelable -> putParcelable(key, value) // Scalar arrays is BooleanArray -> putBooleanArray(key, value) is ByteArray -> putByteArray(key, value) is CharArray -> putCharArray(key, value) is DoubleArray -> putDoubleArray(key, value) is FloatArray -> putFloatArray(key, value) is IntArray -> putIntArray(key, value) is LongArray -> putLongArray(key, value) is ShortArray -> putShortArray(key, value) // Reference arrays is Array<*> -> { val componentType = value::class.java.componentType @Suppress("UNCHECKED_CAST") // Checked by reflection. when { Parcelable::class.java.isAssignableFrom(componentType) -> { putParcelableArray(key, value as Array<Parcelable>) } String::class.java.isAssignableFrom(componentType) -> { putStringArray(key, value as Array<String>) } CharSequence::class.java.isAssignableFrom(componentType) -> { putCharSequenceArray(key, value as Array<CharSequence>) } Serializable::class.java.isAssignableFrom(componentType) -> { putSerializable(key, value) } else -> { val valueType = componentType.canonicalName throw IllegalArgumentException( "Illegal value array type $valueType for key "$key"") }5 }6 }7 // Last resort. Also we must check this after Array<*> as all arrays are serializable. is Serializable -> putSerializable(key, value) else -> { if (Build.VERSION.SDK_INT >= 18 && value is Binder) { putBinder(key, value) } else if (Build.VERSION.SDK_INT >= 21 && value is Size) { putSize(key, value) } else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) { putSizeF(key, value) } else { val valueType = value.javaClass.canonicalName throw IllegalArgumentException("Illegal value type $valueType for key "$key"") }1 }2 }3 }4 }5
  • 38. fun bundleOf(vararg pairs: Pair<String, Any?>) = Bundle(pairs.size).apply { for ((key, value) in pairs) { when (value) { null -> putString(key, null) // Any nullable type will suffice. // Scalars is Boolean -> putBoolean(key, value) is Byte -> putByte(key, value) is Char -> putChar(key, value) is Double -> putDouble(key, value) is Float -> putFloat(key, value) is Int -> putInt(key, value) is Long -> putLong(key, value) is Short -> putShort(key, value) // References is Bundle -> putBundle(key, value) is CharSequence -> putCharSequence(key, value) is Parcelable -> putParcelable(key, value) // Scalar arrays is BooleanArray -> putBooleanArray(key, value) is ByteArray -> putByteArray(key, value) is CharArray -> putCharArray(key, value) is DoubleArray -> putDoubleArray(key, value) is FloatArray -> putFloatArray(key, value) is IntArray -> putIntArray(key, value) is LongArray -> putLongArray(key, value)
  • 39. } Serializable::class.java.isAssignableFrom(componentType) -> { putSerializable(key, value) } else -> { val valueType = componentType.canonicalName throw IllegalArgumentException( "Illegal value array type $valueType for key "$key"") }5 }6 }7 // Last resort. Also we must check this after Array<*> as all arrays are serializable. is Serializable -> putSerializable(key, value) else -> { if (Build.VERSION.SDK_INT >= 18 && value is Binder) { putBinder(key, value) } else if (Build.VERSION.SDK_INT >= 21 && value is Size) { putSize(key, value) } else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) { putSizeF(key, value) } else { val valueType = value.javaClass.canonicalName throw IllegalArgumentException("Illegal value type $valueType for key "$key"") }1 }2 }3 }4 }5
  • 40. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { fun newInstance(param: T) : Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8 val Fragment.param: T get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T }2 }1
  • 41. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { val Fragment.param: T get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T }2 }1 fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment { return factory().apply { arguments = bundleOf(MY_PARAM to param) }7 }8
  • 42. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { val Fragment.param: T get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T }2 }1 fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment { return factory().apply {4 arguments = Bundle().apply {5 putParcelable(MY_PARAM, param) }6 }7 }8
  • 43. private const val MY_PARAM = "my_param" open class FragmentCreator<T>( val factory: () -> Fragment ) { val Fragment.param: T get() = arguments!!.get(MY_PARAM) as T fun param(fragment: Fragment): T { return fragment.arguments!!.get(MY_PARAM) as T }2 }1 fun <T : Parcelable> FragmentCreator<T>.newInstance(param: T): Fragment { return factory().apply {4 arguments = Bundle().apply {5 putParcelable(MY_PARAM, param) }6 }7 }8 fun FragmentCreator<String>.newInstance(param: String): Fragment { return factory().apply { arguments = Bundle().apply { putString(MY_PARAM, param) } } }
  • 45. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) myTextView.text = "Loading..." Thread.sleep(2000) myTextView.text = "Loading something else..." Thread.sleep(2000) myTextView.text = "Done" }_
  • 46. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) myTextView.text = "Loading..." Thread.sleep(2000) myTextView.text = "Loading something else..." Thread.sleep(2000) myTextView.text = "Done" }_
  • 47. /** * Delays coroutine for a given time without blocking * a thread and resumes it after a specified time. * ... */ suspend fun delay(time: Long, unit: TimeUnit = MILLISECONDS) { //... }
  • 49. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) launch(UI) { myTextView.text = "Loading..." delay(2000) myTextView.text = "Loading something else..." delay(2000) myTextView.text = "Done" }async }end
  • 50. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) launch(UI) { myTextView.text = "Loading..." delay(2000) myTextView.text = "Loading something else..." delay(2000) myTextView.text = "Done" }async }end
  • 51. class MyService { fun loadData(): String { //... return slowMethod() }1 private fun slowMethod(): String { //... }2 }3
  • 52. class MyService { suspend fun loadData(): String { return withContext(CommonPool) { //... slowMethod() }5 }1 private fun slowMethod(): String { //... }2 }3
  • 53. class MyViewModel( private val service: MyService ) : ViewModel() { private val job = Job() fun load() { launch(CommonPool + job) { try { val data = service.loadData() updateUi(data) } catch (e: Exception) { updateUi(e.message) }1 }2 }3 private suspend fun updateUi(s: String?) { withContext(UI) { //... }4 }5 override fun onCleared() { job.cancel() }6 }7
  • 54. class MyViewModel( private val service: MyService ) : ViewModel() { private val job = Job() fun load() { launch(CommonPool + job) { try { val data = service.loadData() updateUi(data) } catch (e: Exception) { updateUi(e.message) }1 }2 }3 private suspend fun updateUi(s: String?) { withContext(UI) { //... }4 }5 override fun onCleared() { job.cancel() }6 }7
  • 55. class MyViewModel( private val service: MyService ) : ViewModel() { private val job = Job() fun load() { launch(CommonPool + job) { try { val data = service.loadData() updateUi(data) } catch (e: Exception) { updateUi(e.message) }1 }2 }3 private suspend fun updateUi(s: String?) { withContext(UI) { //... }4 }5 override fun onCleared() { job.cancel() }6 }7
  • 56. class MyViewModel( private val service: MyService ) : ViewModel() { private val job = Job() fun load() { launch(CommonPool + job) { try { val data = service.loadData() updateUi(data) } catch (e: Exception) { updateUi(e.message) }1 }2 }3 private suspend fun updateUi(s: String?) { withContext(UI) { //... }4 }5 override fun onCleared() { job.cancel() }6 }7
  • 57. class MyViewModel( private val service: MyService ) : ViewModel() { private val job = Job() fun load() { launch(CommonPool + job) { try { val data = service.loadData() updateUi(data) } catch (e: Exception) { updateUi(e.message) }1 }2 }3 private suspend fun updateUi(s: String?) { withContext(UI) { //... }4 }5 override fun onCleared() { job.cancel() }6 }7
  • 58. interface MyService { @GET("login") fun login(): Deferred<String> @GET("data") fun loadData(@Query(“token") token: String): Deferred<Data> }A
  • 59. interface MyService { @GET("login") fun login(): Deferred<String> @GET("data") fun loadData(@Query(“token") token: String): Deferred<Data> }A launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data) } catch (e: Exception) { showError(e) }__ }___
  • 60. service.login() .flatMap { service.loadData(it) } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { data -> showInUi(data) }, { showError(it) } )end RxJavaCoroutines launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data) } catch (e: Exception) { showError(e) }__ }___
  • 63. RxJava Coroutines-> RxJavaCoroutines -> rxCompletable, rxMaybe, rxSingle, rxObservable, rxFlowable CompletableSource.await, MaybeSource.await, MaybeSource.awaitOrDefault, MaybeSource.openSubscription, SingleSource.await, ObservableSource.awaitFirst, ObservableSource.awaitFirstOrDefault, ObservableSource.awaitFirstOrElse, ObservableSource.awaitFirstOrNull, ObservableSource.awaitLast, ObservableSource.awaitSingle, ObservableSource.openSubscription, ObservableSource.iterator github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx2
  • 64. launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data)1 } catch (e: Exception) { showError(e) }__ }___
  • 65. launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data)1 } catch (e: Exception) { showError(e) }__ }___
  • 66. launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token).await() val otherData = service.loadOtherData(token).await() showInUi(data, otherData)1 } catch (e: Exception) { showError(e) }__ }___
  • 67. launch(CommonPool) { try { val token = service.login().await() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await())1 } catch (e: Exception) { showError(e) }__ }___
  • 68. launch(CommonPool) { try { val token = service.login().await() updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) } catch (e: Exception) { showError(e) }__ }___
  • 69. launch(CommonPool) { try { withTimeout(10, SECONDS) { val token = service.login().await() updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) }B } catch (e: Exception) { showError(e) }__ }___
  • 70. launch(CommonPool) { try { withTimeout(10, SECONDS) { val token = retry(3) { service.login().await() }T updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) }B } catch (e: Exception) { showError(e) }__ }___
  • 71. launch(CommonPool) { try { withTimeout(10, SECONDS) { val token = retry(3) { service.login().await() }T updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) }B } catch (e: Exception) { showError(e) }__ }___ suspend fun <T> retry(times: Int, f: suspend () -> T): T { repeat(times - 1) { try { return f() } catch (ignored: Exception) { } } return f() }
  • 72. launch(CommonPool) { try { withTimeout(10, SECONDS) { val token = exponentialBackoff(3) { service.login().await() }T updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) }B } catch (e: Exception) { showError(e) }__ }___
  • 73. launch(CommonPool) { try { withTimeout(10, SECONDS) { val token = exponentialBackoff(3) { service.login().await() }T updateProgress() val data = service.loadData(token) val otherData = service.loadOtherData(token) showInUi(data.await(), otherData.await()) }B } catch (e: Exception) { showError(e) }__ }___ suspend fun <T> exponentialBackoff(times: Int, f: suspend () -> T): T { var currentDelay = 100 + Random().nextInt(100) repeat(times - 1) { try { return f() } catch (e: Exception) { } delay(currentDelay) currentDelay *= 2 } return f() }
  • 74. launch executes a task on a coroutine context an uncaught exception stops the app used to start a computation Deferred await returns the result or throws an exception can be used to execute something in parallel can be created using async withContext suspending method changes the execution thread useful to force the execution of a method on a thread
  • 75. My 2 cents Suspending methods are easier to use than RxJava Singles Observables/Flowables are the best abstraction for a stream of data
  • 77. class TokenHolder {0 var token = "" }1
  • 78. class TokenHolder {0 var token = "" }1 public class TokenHolder { private String token = ""; public String getToken() { return this.token; }1 public void setToken(String token) { this.token = token; }2 }3
  • 79. class TokenHolder {0 var token = "" }1
  • 80. class TokenHolder(private val prefs: SharedPreferences) {0 var token = "" }1
  • 81. class TokenHolder(private val prefs: SharedPreferences) { var token get() = prefs.getString("token", "") set(value) = prefs.edit().putString("token", value).apply() }1
  • 82. class TokenHolder(private val prefs: SharedPreferences) { var token get() = prefs.getString("token", "") set(value) = prefs.edit().putString("token", value).apply() }1 public class TokenHolder { private final SharedPreferences prefs; public TokenHolder(SharedPreferences prefs) { this.prefs = prefs; }1 public final String getToken() { return this.prefs.getString("token", ""); }2 public final void setToken(String value) { this.prefs.edit().putString("token", value).apply(); }3 }4
  • 83. class TokenHolder(private val prefs: SharedPreferences) { var token get() = prefs.getString("token", "") set(value) = prefs.edit().putString("token", value).apply() }1
  • 84. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1
  • 85. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1 fun SharedPreferences.string(): ReadWriteProperty<Any, String> { return object : ReadWriteProperty<Any, String> { override fun getValue(thisRef: Any, property: KProperty<*>): String { return getString(property.name, "") }2 override fun setValue(thisRef: Any, property: KProperty<*>, value: String) { edit().putString(property.name, value).apply() }3 }4 }5
  • 86. fun SharedPreferences.string( defaultValue: String = "" ): ReadWriteProperty<Any, String> { return object : ReadWriteProperty<Any, String> { override fun getValue(thisRef: Any, property: KProperty<*>): String { return getString(property.name, defaultValue) }2 override fun setValue(thisRef: Any, property: KProperty<*>, value: String) { edit().putString(property.name, value).apply() }3 }4 }5 class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1
  • 87. fun SharedPreferences.string( defaultValue: String = "", key: String? = null ): ReadWriteProperty<Any, String> { return object : ReadWriteProperty<Any, String> { override fun getValue(thisRef: Any, property: KProperty<*>): String { return getString(key ?: property.name, defaultValue) }2 override fun setValue(thisRef: Any, property: KProperty<*>, value: String) { edit().putString(key ?: property.name, value).apply() }3 }4 }5 class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1
  • 88. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1 public class TokenHolder { static final KProperty delegatedProperty = //.. private final ReadWriteProperty token$delegate; public TokenHolder(SharedPreferences prefs) { this.token$delegate = PrefsKt.string(prefs, null, null); }1 public final String getToken() { return (String)token$delegate.getValue(this, delegatedProperty); }2 public final void setToken(String var1) { token$delegate.setValue(this, delegatedProperty, var1); }3 }4
  • 89. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1 tokenHolder.token += "ABC" prefs.edit().putString( "token", prefs.getString("token", "") + "ABC" ).apply()
  • 90. Wrapping up Alt+Shift+Cmd+K is just the beginning functional code is natural in Kotlin code can be simplified using companion objects, coroutines and delegates
  • 91. Links Demo Project github.com/fabioCollini/ArchitectureComponentsDemo Libraries Lightweight Stream github.com/aNNiMON/Lightweight-Stream-API Guides and posts Guide to kotlinx.coroutines by example github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md Async code using Kotlin Coroutines proandroiddev.com/async-code-using-kotlin-coroutines-233d201099ff Kotlin delegates in Android development part 1 hackernoon.com/kotlin-delegates-in-android-development-part-1-50346cf4aed7 Kotlin delegates in Android development part 2 proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438
  翻译: