SlideShare a Scribd company logo
1 of 93
Download to read offline
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)
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

More Related Content

What's hot

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. ExperienceMike 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, objectsHusain 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 reduxEleanor 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 181Mahmoud Samir Fayed
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragmentChiwon Song
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programmingChiwon Song
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The WildStackMob Inc
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureMike Fogus
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order functionChiwon 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 HackersEleanor McHugh
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Baruch Sadogursky
 

What's hot (20)

SDC - Einführung in Scala
SDC - Einführung in ScalaSDC - Einführung in Scala
SDC - Einführung in Scala
 
Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
RxSwift 시작하기
RxSwift 시작하기RxSwift 시작하기
RxSwift 시작하기
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
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
 
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
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragment
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
 
Monad Transformers In The Wild
Monad Transformers In The WildMonad Transformers In The Wild
Monad Transformers In The Wild
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
 
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
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 

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

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 Waytdc-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 GoogleEleanor McHugh
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresiMasters
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsFranco 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 3Kirill 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+kFabio 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 2018Codemotion
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry 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 ...Databricks
 
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
 
つくってあそぼ 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, MyHeritageDroidConTLV
 

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
 
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
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
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
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
Kotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functionsKotlin from-scratch 2 - functions
Kotlin from-scratch 2 - functions
 
ハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使うハイブリッド言語Scalaを使う
ハイブリッド言語Scalaを使う
 
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
 
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
 
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
 
Kotlin, why?
Kotlin, why?Kotlin, why?
Kotlin, why?
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
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 ...
 
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...
 
つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~つくってあそぼ Kotlin DSL ~拡張編~
つくってあそぼ Kotlin DSL ~拡張編~
 
JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?JDD 2016 - Pawel Byszewski - Kotlin, why?
JDD 2016 - Pawel Byszewski - Kotlin, why?
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
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
 

More from Fabio Collini

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose worldFabio Collini
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized projectFabio Collini
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutinesFabio 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 confFabio 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 StockholmFabio 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 projectFabio 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 ItalyFabio 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 RomagnaFabio 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 ArchitectureFabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018Fabio 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 UKFabio Collini
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Fabio 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 RxJavaFabio 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 - droidconUKFabio 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 patternFabio Collini
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeFabio 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 MVVMFabio Collini
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaFabio Collini
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Fabio Collini
 

More from Fabio Collini (20)

Architectures in the compose world
Architectures in the compose worldArchitectures in the compose world
Architectures in the compose world
 
Using hilt in a modularized project
Using hilt in a modularized projectUsing hilt in a modularized project
Using hilt in a modularized project
 
Managing parallelism using coroutines
Managing parallelism using coroutinesManaging parallelism using coroutines
Managing parallelism using coroutines
 
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
 
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
 
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
 
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
 
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
 
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
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
 
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
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 
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
 
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
 
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
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
 
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
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
 

Recently uploaded

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - InfographicHr365.us smith
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 

Recently uploaded (20)

The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Asset Management Software - Infographic
Asset Management Software - InfographicAsset Management Software - Infographic
Asset Management Software - Infographic
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 

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)
  • 10.
  • 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