SlideShare a Scribd company logo
1 of 94
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?
CLASSES
DATA COLLE
CTIONS
ASYNC
CODE
DELE
GATES
Agenda
COMPANION
OBJECTS
DATA
CLASSES
@Parcelize
data class Person(
val id: Long,
val name: String,
val age: Int
)_: Parcelable
@Parcelize
data class Person(
val id: Long,
val name: String,
val age: Int
)_: Parcelable
public class Person implements Parcelable {
private long id;
private String name;
private int age;
public Person(long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}1
protected Person(Parcel in) {
id = in.readLong();
name = in.readString();
age = in.readInt();
}2
public long getId()_{_return id;_}
public String getName()_{_return name;_}
public int getAge()_{_return age;_}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person that = (Person) o;
if (id != that.id) return false;
if (age != that.age) return false;
return name != null ? name.equals(that.name) : that.name == null;
}3
@Override public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
return result;
}4
@Override public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + ''' +
", age=" + age +
'}';
}5
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(name);
dest.writeInt(age);
}6
@Override
public int describeContents() {
return 0;
}7
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}8
@Override
public Person[] newArray(int size) {
return new Person[size];
}9
};
}_
@AutoValue
public abstract class Person
implements Parcelable {_
public static Person create(
long id, String name, int age) {
return new AutoValue_Person(
id, name, age);
}__
public abstract long id();
public abstract String name();
public abstract int age();
}1
@AutoValue
public abstract class Person
implements Parcelable {_
public static Person create(
long id, String name, int age) {
return new AutoValue_Person(
id, name, age);
}__
public abstract long id();
public abstract String name();
public abstract int age();
public abstract Person withName(String name);
}1
@AutoValue
public abstract class Person
implements Parcelable {_
public static Person create(
long id, String name, int age) {
return new AutoValue_Person(
id, name, age);
}__
public abstract long id();
public abstract String name();
public abstract int age();
public abstract Person withName(String name);
}1
@Parcelize
data class Person(
val id: Long,
val name: String,
val age: Int
)_: Parcelable
val p = Person(1, "name", 10)
val p1 = p.copy(name = "newName", age = 20)_
Person p = Person.create(1, "name", 10);
Person p1 = p.withName("newName");
data class City(
val name: String,
val code: String,
val region: String
)endCity
data class Street(
val name: String,end
val number: String
)endStreet
data class Address(
val street: Street,
val city: City
)endAddress
data class Person(
val id: Long,
val name: String,
val age: Int,
val address: Address
)endPerson
val p = Person(1, "name", 10,
Address(
Street("myStreet", "1/F"),
City("Florence", "FI", "Tuscany")
)_
)__
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
Nested copy
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
Nested copy
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
Local variablesNested copy
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
Nested copy Local variables
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
val personStreetName: Lens<Person, String> =
personAddress compose
addressStreet compose streetName
val p1 = personStreetName.modify(p) {
"newStreetName"
}_
Arrow - Lenses
Nested copy Local variables
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
val personStreetName: Lens<Person, String> =
personAddress compose
addressStreet compose streetName
val p1 = personStreetName.modify(p) {
"newStreetName"
}_
Nested copy Local variables
Arrow - Lenses
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
val personStreetName: Lens<Person, String> =
personAddress compose
addressStreet compose streetName
val p1 = personStreetName.modify(p) {
"newStreetName"
}_
val p1 = p.deepCopy(
{ address }, { copy(address = it) },
{ street }, { copy(street = it) },
{ copy(name = "myNewStreet") }
)
inline fun <C1, C2, C3> C1.deepCopy(
field1: C1.() -> C2, f1: C1.(C2) -> C1,
field2: C2.() -> C3, f2: C2.(C3) -> C2,
f: C3.(C2) -> C3): C1 {
val value2 = field1()
val value3 = value2.field2()
val newValue3 = value3.f(value2)
val newValue2 = value2.f2(newValue3)
return f1(newValue2)
}1
inline fun <C1, C2, C3, C4> C1.deepCopy(
field1: C1.() -> C2, f1: C1.(C2) -> C1,
field2: C2.() -> C3, f2: C2.(C3) -> C2,
field3: C3.() -> C4, f3: C3.(C4) -> C3,
f: C4.(C3) -> C4): C1 {
val value2 = field1()
val value3 = value2.field2()
val value4 = value3.field3()
val newValue4 = value4.f(value3)
val newValue3 = value3.f3(newValue4)
val newValue2 = value2.f2(newValue3)
return f1(newValue2)
}
inline fun <C1, C2> C1.deepCopy(
field1: C1.() -> C2, f1: C1.(C2) -> C1,
f: C2.(C1) -> C2): C1 {
val value2 = field1()
val newValue2 = value2.f(this)
return f1(newValue2)
}
Nested copy Local variables
Arrow - Lenses
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
val personStreetName: Lens<Person, String> =
personAddress compose
addressStreet compose streetName
val p1 = personStreetName.modify(p) {
"newStreetName"
}_
val p1 = p.deepCopy(
{ address }, { copy(address = it) },
{ street }, { copy(street = it) },
{ copy(name = "myNewStreet") }
)__
Object $receiver$iv = p;
Object value2$iv = $receiver$iv.getAddress();
Object value3$iv = value2$iv.getStreet();
Object newValue3$iv = Street.copy$default(value3$iv, "myNewStreet", (String) null, 2, (Object) null);
Object newValue2$iv = Address.copy$default(value2$iv, newValue3$iv, (City) null, 2, (Object) null);
Person p2 = Person.copy$default($receiver$iv, 0L, (String) null, 0, newValue2$iv, 7, (Object) null);
val p1 = p.deepCopy(
{ address }, { copy(address = it) },
{ street }, { copy(street = it) },
{ copy(name = "myNewStreet") }
)__
Address address = p.getAddress();
Street street = address.getStreet();
Street newStreet = street.copy("myNewStreet", street.getNumber());
Address newAddress = address.copy(newStreet, address.getCity());
Person p2 = p.copy(p.getId(), p.getName(), p.getAge(), newAddress);
val p1 = p.deepCopy(
{ address }, { copy(address = it) },
{ street }, { copy(street = it) },
{ copy(name = "myNewStreet") }
)__
val p1 = p.deepCopy(
{ address }, { copy(address = it) },
{ street }, { copy(street = it) },
{ copy(name = "myNewStreet") }
)__
inline method
Nested copy Local variables
Arrow - Lenses
val p1 = p.copy(
address = p.address.copy(
street = p.address.street.copy(
name = "myNewStreet"
)1
)2
)3
val address = p.address
val street = address.street
val newStreet = street.copy(name = "myNewStreet")
val newAddress = address.copy(street = newStreet)
val p1 = p.copy(address = newAddress)
val personStreetName: Lens<Person, String> =
personAddress compose
addressStreet compose streetName
val p1 = personStreetName.modify(p) {
"newStreetName"
}_
val p = Person(1, "name", 10)
val (_, name, age) = p
println("$name $age")
data class Pair<out A, out B>(
val first: A,
val second: B
) : Serializable {
override fun toString(): String = "($first, $second)"
}_
data class Pair<out A, out B>(
val first: A,
val second: B
) : Serializable {
override fun toString(): String = "($first, $second)"
}_
val myPair: Pair<Int, Int> = Pair(10, 20)
val otherPair: Pair<Int, Int> = 10 to 20
infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
fun myMethod(): Pair<Int, Int> {
//...
return 10 to 20
}
val (a, b) = myMethod()
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
.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 }
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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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 = new Bundle();
bundle.putString("my_param", param);
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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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 = new Bundle();
bundle.putString("my_param", param);
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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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);
}1
public static final class Companion {
public final MyFragment newInstance(String param) {
MyFragment fragment = new MyFragment();
Bundle bundle = new Bundle();
bundle.putString("my_param", param);
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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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 = Bundle().apply {
putString(MY_PARAM, param)
}6
}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 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 {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)
async(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)
async(UI) {
myTextView.text = "Loading..."
delay(2000)
myTextView.text = "Loading something else..."
delay(2000)
myTextView.text = "Done"
}async
}end
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
async(UI) {
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
async(UI) {
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
async(UI) {
try {
val token = service.login().await()
val data = service.loadData(token).await()
showInUi(data)1
} catch (e: Exception) {
showError(e)
}__
}___
async(UI) {
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)
}__
}___
async(UI) {
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)
}__
}___
async(UI) {
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)
}__
}___
async(UI) {
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)
}__
}___
async(UI) {
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)
}__
}___
async(UI) {
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, block: suspend () -> T): T {
repeat(times - 1) {
try {
return block()
} catch (ignored: Exception) {
}
}
return block()
}
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
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, data classes,
coroutines and delegates
Links Demo Project
github.com/fabioCollini/ArchitectureComponentsDemo
Libraries
AutoValue github.com/google/auto/blob/master/value/userguide/index.md
Lightweight Stream github.com/aNNiMON/Lightweight-Stream-API
Arrow arrow-kt.io/
Guides and posts
Guide to kotlinx.coroutines by example
github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md
Kotlin coroutines, a deeper look
medium.com/@elizarov/kotlin-coroutines-a-deeper-look-180536305c3f
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
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. ExperienceMike Fogus
 
Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)진성 오
 
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
 
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
 
6. Generics. Collections. Streams
6. Generics. Collections. Streams6. Generics. Collections. Streams
6. Generics. Collections. StreamsDEVTYPE
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragmentChiwon Song
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickHermann Hueck
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programmingChiwon Song
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order functionChiwon Song
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureMike Fogus
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?osfameron
 

What's hot (20)

Code as data as code.
Code as data as code.Code as data as code.
Code as data as code.
 
Naïveté vs. Experience
Naïveté vs. ExperienceNaïveté vs. Experience
Naïveté vs. Experience
 
Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)Swift에서 꼬리재귀 사용기 (Tail Recursion)
Swift에서 꼬리재귀 사용기 (Tail Recursion)
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
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
 
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
 
Kotlin standard
Kotlin standardKotlin standard
Kotlin standard
 
6. Generics. Collections. Streams
6. Generics. Collections. Streams6. Generics. Collections. Streams
6. Generics. Collections. Streams
 
20180721 code defragment
20180721 code defragment20180721 code defragment
20180721 code defragment
 
Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015Pooya Khaloo Presentation on IWMC 2015
Pooya Khaloo Presentation on IWMC 2015
 
Implementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with SlickImplementing a many-to-many Relationship with Slick
Implementing a many-to-many Relationship with Slick
 
Scala 2 + 2 > 4
Scala 2 + 2 > 4Scala 2 + 2 > 4
Scala 2 + 2 > 4
 
20180310 functional programming
20180310 functional programming20180310 functional programming
20180310 functional programming
 
PDBC
PDBCPDBC
PDBC
 
Javascript
JavascriptJavascript
Javascript
 
20181020 advanced higher-order function
20181020 advanced higher-order function20181020 advanced higher-order function
20181020 advanced higher-order function
 
Kotlin class
Kotlin classKotlin class
Kotlin class
 
Fertile Ground: The Roots of Clojure
Fertile Ground: The Roots of ClojureFertile Ground: The Roots of Clojure
Fertile Ground: The Roots of Clojure
 
はじめてのGroovy
はじめてのGroovyはじめてのGroovy
はじめてのGroovy
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
 

Similar to From java to kotlin beyond alt+shift+cmd+k - Droidcon italy

Type script by Howard
Type script by HowardType script by Howard
Type script by HowardLearningTech
 
TypeScript by Howard
TypeScript by HowardTypeScript by Howard
TypeScript by HowardLearningTech
 
Howard type script
Howard   type scriptHoward   type script
Howard type scriptLearningTech
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesNebojša Vukšić
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)HamletDRC
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodecamp Romania
 
Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Daniel Pokusa
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Codemotion
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Suyeol Jeon
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6Moaid Hathot
 
Speed up the mobile development process
Speed up the mobile development processSpeed up the mobile development process
Speed up the mobile development processLeonardoSarra
 
An Introduction to Scala (2014)
An Introduction to Scala (2014)An Introduction to Scala (2014)
An Introduction to Scala (2014)William Narmontas
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo....NET Conf UY
 
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
 

Similar to From java to kotlin beyond alt+shift+cmd+k - Droidcon italy (20)

Type script by Howard
Type script by HowardType script by Howard
Type script by Howard
 
TypeScript by Howard
TypeScript by HowardTypeScript by Howard
TypeScript by Howard
 
Howard type script
Howard   type scriptHoward   type script
Howard type script
 
First few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examplesFirst few months with Kotlin - Introduction through android examples
First few months with Kotlin - Introduction through android examples
 
ddd+scala
ddd+scaladdd+scala
ddd+scala
 
Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)Groovy Ast Transformations (greach)
Groovy Ast Transformations (greach)
 
Introduction to Scala
Introduction to ScalaIntroduction to Scala
Introduction to Scala
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
CodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical GroovyCodeCamp Iasi 10 march 2012 - Practical Groovy
CodeCamp Iasi 10 march 2012 - Practical Groovy
 
Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!Java: Nie popełniaj tych błędów!
Java: Nie popełniaj tych błędów!
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 
Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
Pure kotlin
Pure kotlinPure kotlin
Pure kotlin
 
Best of build 2021 - C# 10 & .NET 6
Best of build 2021 -  C# 10 & .NET 6Best of build 2021 -  C# 10 & .NET 6
Best of build 2021 - C# 10 & .NET 6
 
Benefits of Kotlin
Benefits of KotlinBenefits of Kotlin
Benefits of Kotlin
 
Speed up the mobile development process
Speed up the mobile development processSpeed up the mobile development process
Speed up the mobile development process
 
An Introduction to Scala (2014)
An Introduction to Scala (2014)An Introduction to Scala (2014)
An Introduction to Scala (2014)
 
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
Code Smells y Refactoring o haciendo que nuestro codigo huela (y se vea) mejo...
 
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
 

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

(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...ranjana rawat
 
Coefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxCoefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxAsutosh Ranjan
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130Suhani Kapoor
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINESIVASHANKAR N
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCall Girls in Nagpur High Profile
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxupamatechverse
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Christo Ananth
 
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSAPPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSKurinjimalarL3
 
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝soniya singh
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxthe ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxhumanexperienceaaa
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Dr.Costas Sachpazis
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVRajaP95
 
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130Suhani Kapoor
 
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...srsj9000
 
GDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSCAESB
 
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...Soham Mondal
 
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)Suman Mia
 

Recently uploaded (20)

(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
(SHREYA) Chakan Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Esc...
 
Coefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxCoefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptx
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
 
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINEMANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
MANUFACTURING PROCESS-II UNIT-2 LATHE MACHINE
 
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service NashikCollege Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
College Call Girls Nashik Nehal 7001305949 Independent Escort Service Nashik
 
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCRCall Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptx
 
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
Call for Papers - African Journal of Biological Sciences, E-ISSN: 2663-2187, ...
 
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSAPPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
 
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Narela Delhi reach out to us at 🔝8264348440🔝
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
 
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptxthe ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
the ladakh protest in leh ladakh 2024 sonam wangchuk.pptx
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
 
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
VIP Call Girls Service Kondapur Hyderabad Call +91-8250192130
 
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
Gfe Mayur Vihar Call Girls Service WhatsApp -> 9999965857 Available 24x7 ^ De...
 
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptxExploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
Exploring_Network_Security_with_JA3_by_Rakesh Seal.pptx
 
GDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentationGDSC ASEB Gen AI study jams presentation
GDSC ASEB Gen AI study jams presentation
 
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
OSVC_Meta-Data based Simulation Automation to overcome Verification Challenge...
 
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)Software Development Life Cycle By  Team Orange (Dept. of Pharmacy)
Software Development Life Cycle By Team Orange (Dept. of Pharmacy)
 

From java to kotlin beyond alt+shift+cmd+k - Droidcon italy

  • 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. @Parcelize data class Person( val id: Long, val name: String, val age: Int )_: Parcelable
  • 9. @Parcelize data class Person( val id: Long, val name: String, val age: Int )_: Parcelable public class Person implements Parcelable { private long id; private String name; private int age; public Person(long id, String name, int age) { this.id = id; this.name = name; this.age = age; }1 protected Person(Parcel in) { id = in.readLong(); name = in.readString(); age = in.readInt(); }2 public long getId()_{_return id;_} public String getName()_{_return name;_} public int getAge()_{_return age;_} @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person that = (Person) o; if (id != that.id) return false; if (age != that.age) return false; return name != null ? name.equals(that.name) : that.name == null; }3 @Override public int hashCode() { int result = (int) (id ^ (id >>> 32)); result = 31 * result + (name != null ? name.hashCode() : 0); result = 31 * result + age; return result; }4 @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + ''' + ", age=" + age + '}'; }5 @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(name); dest.writeInt(age); }6 @Override public int describeContents() { return 0; }7 public static final Creator<Person> CREATOR = new Creator<Person>() { @Override public Person createFromParcel(Parcel in) { return new Person(in); }8 @Override public Person[] newArray(int size) { return new Person[size]; }9 }; }_
  • 10. @AutoValue public abstract class Person implements Parcelable {_ public static Person create( long id, String name, int age) { return new AutoValue_Person( id, name, age); }__ public abstract long id(); public abstract String name(); public abstract int age(); }1
  • 11. @AutoValue public abstract class Person implements Parcelable {_ public static Person create( long id, String name, int age) { return new AutoValue_Person( id, name, age); }__ public abstract long id(); public abstract String name(); public abstract int age(); public abstract Person withName(String name); }1
  • 12. @AutoValue public abstract class Person implements Parcelable {_ public static Person create( long id, String name, int age) { return new AutoValue_Person( id, name, age); }__ public abstract long id(); public abstract String name(); public abstract int age(); public abstract Person withName(String name); }1 @Parcelize data class Person( val id: Long, val name: String, val age: Int )_: Parcelable
  • 13. val p = Person(1, "name", 10) val p1 = p.copy(name = "newName", age = 20)_ Person p = Person.create(1, "name", 10); Person p1 = p.withName("newName");
  • 14. data class City( val name: String, val code: String, val region: String )endCity data class Street( val name: String,end val number: String )endStreet data class Address( val street: Street, val city: City )endAddress data class Person( val id: Long, val name: String, val age: Int, val address: Address )endPerson
  • 15. val p = Person(1, "name", 10, Address( Street("myStreet", "1/F"), City("Florence", "FI", "Tuscany") )_ )__ val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3
  • 16. val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 Nested copy
  • 17. val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) Nested copy val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3
  • 18. val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) Local variablesNested copy val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3
  • 19. Nested copy Local variables val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) val personStreetName: Lens<Person, String> = personAddress compose addressStreet compose streetName val p1 = personStreetName.modify(p) { "newStreetName" }_
  • 20. Arrow - Lenses Nested copy Local variables val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) val personStreetName: Lens<Person, String> = personAddress compose addressStreet compose streetName val p1 = personStreetName.modify(p) { "newStreetName" }_
  • 21. Nested copy Local variables Arrow - Lenses val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) val personStreetName: Lens<Person, String> = personAddress compose addressStreet compose streetName val p1 = personStreetName.modify(p) { "newStreetName" }_ val p1 = p.deepCopy( { address }, { copy(address = it) }, { street }, { copy(street = it) }, { copy(name = "myNewStreet") } )
  • 22. inline fun <C1, C2, C3> C1.deepCopy( field1: C1.() -> C2, f1: C1.(C2) -> C1, field2: C2.() -> C3, f2: C2.(C3) -> C2, f: C3.(C2) -> C3): C1 { val value2 = field1() val value3 = value2.field2() val newValue3 = value3.f(value2) val newValue2 = value2.f2(newValue3) return f1(newValue2) }1 inline fun <C1, C2, C3, C4> C1.deepCopy( field1: C1.() -> C2, f1: C1.(C2) -> C1, field2: C2.() -> C3, f2: C2.(C3) -> C2, field3: C3.() -> C4, f3: C3.(C4) -> C3, f: C4.(C3) -> C4): C1 { val value2 = field1() val value3 = value2.field2() val value4 = value3.field3() val newValue4 = value4.f(value3) val newValue3 = value3.f3(newValue4) val newValue2 = value2.f2(newValue3) return f1(newValue2) } inline fun <C1, C2> C1.deepCopy( field1: C1.() -> C2, f1: C1.(C2) -> C1, f: C2.(C1) -> C2): C1 { val value2 = field1() val newValue2 = value2.f(this) return f1(newValue2) }
  • 23. Nested copy Local variables Arrow - Lenses val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) val personStreetName: Lens<Person, String> = personAddress compose addressStreet compose streetName val p1 = personStreetName.modify(p) { "newStreetName" }_ val p1 = p.deepCopy( { address }, { copy(address = it) }, { street }, { copy(street = it) }, { copy(name = "myNewStreet") } )__
  • 24. Object $receiver$iv = p; Object value2$iv = $receiver$iv.getAddress(); Object value3$iv = value2$iv.getStreet(); Object newValue3$iv = Street.copy$default(value3$iv, "myNewStreet", (String) null, 2, (Object) null); Object newValue2$iv = Address.copy$default(value2$iv, newValue3$iv, (City) null, 2, (Object) null); Person p2 = Person.copy$default($receiver$iv, 0L, (String) null, 0, newValue2$iv, 7, (Object) null); val p1 = p.deepCopy( { address }, { copy(address = it) }, { street }, { copy(street = it) }, { copy(name = "myNewStreet") } )__
  • 25. Address address = p.getAddress(); Street street = address.getStreet(); Street newStreet = street.copy("myNewStreet", street.getNumber()); Address newAddress = address.copy(newStreet, address.getCity()); Person p2 = p.copy(p.getId(), p.getName(), p.getAge(), newAddress); val p1 = p.deepCopy( { address }, { copy(address = it) }, { street }, { copy(street = it) }, { copy(name = "myNewStreet") } )__
  • 26. val p1 = p.deepCopy( { address }, { copy(address = it) }, { street }, { copy(street = it) }, { copy(name = "myNewStreet") } )__ inline method Nested copy Local variables Arrow - Lenses val p1 = p.copy( address = p.address.copy( street = p.address.street.copy( name = "myNewStreet" )1 )2 )3 val address = p.address val street = address.street val newStreet = street.copy(name = "myNewStreet") val newAddress = address.copy(street = newStreet) val p1 = p.copy(address = newAddress) val personStreetName: Lens<Person, String> = personAddress compose addressStreet compose streetName val p1 = personStreetName.modify(p) { "newStreetName" }_
  • 27. val p = Person(1, "name", 10) val (_, name, age) = p println("$name $age")
  • 28. data class Pair<out A, out B>( val first: A, val second: B ) : Serializable { override fun toString(): String = "($first, $second)" }_
  • 29. data class Pair<out A, out B>( val first: A, val second: B ) : Serializable { override fun toString(): String = "($first, $second)" }_ val myPair: Pair<Int, Int> = Pair(10, 20) val otherPair: Pair<Int, Int> = 10 to 20 infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
  • 30. fun myMethod(): Pair<Int, Int> { //... return 10 to 20 } val (a, b) = myMethod()
  • 32. 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<>();
  • 33. 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)
  • 34.
  • 35. 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);
  • 36. val people = listOf(...) val s = people .asSequence() .map { it.address.city } .filter { it.region == "Tuscany" } .map { "${it.name} (${it.code})" } .first() println(s)
  • 37. 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 }
  • 39. 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 = Bundle().apply { putString(MY_PARAM, param) }6 }7 }8 }9 }0
  • 40. 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 = new Bundle(); bundle.putString("my_param", param); 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 = Bundle().apply { putString(MY_PARAM, param) }6 }7 }8 }9 }0
  • 41. 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 = new Bundle(); bundle.putString("my_param", param); 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 = Bundle().apply { putString(MY_PARAM, param) }6 }7 }8 }9 }0
  • 42. 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 = Bundle().apply { putString(MY_PARAM, param) }6 }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); }1 public static final class Companion { public final MyFragment newInstance(String param) { MyFragment fragment = new MyFragment(); Bundle bundle = new Bundle(); bundle.putString("my_param", param); fragment.setArguments(bundle); return fragment; }2 }3 }4
  • 43. 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 = Bundle().apply { putString(MY_PARAM, param) }6 }7 }8 }9 }0
  • 44. 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 = Bundle().apply { putString(MY_PARAM, param) }6 }7 }8 }9 }0
  • 45. 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
  • 46. 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
  • 47. 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
  • 48. 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
  • 49. 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
  • 50. 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")
  • 51. 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
  • 52. 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
  • 53. 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)
  • 54. } 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
  • 55. 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
  • 56. 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
  • 57. 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) } } }
  • 59. 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" }_
  • 60. 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" }_
  • 61. /** * 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) { //... }
  • 63. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) async(UI) { myTextView.text = "Loading..." delay(2000) myTextView.text = "Loading something else..." delay(2000) myTextView.text = "Done" }async }end
  • 64. override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val myTextView = findViewById<TextView>(R.id.text) async(UI) { myTextView.text = "Loading..." delay(2000) myTextView.text = "Loading something else..." delay(2000) myTextView.text = "Done" }async }end
  • 65. interface MyService { @GET("login") fun login(): Deferred<String> @GET("data") fun loadData(@Query(“token") token: String): Deferred<Data> }A
  • 66. interface MyService { @GET("login") fun login(): Deferred<String> @GET("data") fun loadData(@Query(“token") token: String): Deferred<Data> }A async(UI) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data) } catch (e: Exception) { showError(e) }__ }___
  • 67. service.login() .flatMap { service.loadData(it) } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe( { data -> showInUi(data) }, { showError(it) } )end RxJavaCoroutines async(UI) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data) } catch (e: Exception) { showError(e) }__ }___
  • 70. 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
  • 71. async(UI) { try { val token = service.login().await() val data = service.loadData(token).await() showInUi(data)1 } catch (e: Exception) { showError(e) }__ }___
  • 72. async(UI) { 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) }__ }___
  • 73. async(UI) { 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) }__ }___
  • 74. async(UI) { 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) }__ }___
  • 75. async(UI) { 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) }__ }___
  • 76. async(UI) { 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) }__ }___
  • 77. async(UI) { 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, block: suspend () -> T): T { repeat(times - 1) { try { return block() } catch (ignored: Exception) { } } return block() }
  • 78. My 2 cents Suspending methods are easier to use than RxJava Singles Observables/Flowables are the best abstraction for a stream of data
  • 80. class TokenHolder {0 var token = "" }1
  • 81. 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
  • 82. class TokenHolder {0 var token = "" }1
  • 83. class TokenHolder(private val prefs: SharedPreferences) {0 var token = "" }1
  • 84. class TokenHolder(private val prefs: SharedPreferences) { var token get() = prefs.getString("token", "") set(value) = prefs.edit().putString("token", value).apply() }1
  • 85. 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
  • 86. class TokenHolder(private val prefs: SharedPreferences) { var token get() = prefs.getString("token", "") set(value) = prefs.edit().putString("token", value).apply() }1
  • 87. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1
  • 88. 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
  • 89. 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
  • 90. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string() }1 tokenHolder.token += "ABC" prefs.edit().putString( "token", prefs.getString("token", "") + "ABC" ).apply()
  • 91. Wrapping up Alt+Shift+Cmd+K is just the beginning functional code is natural in Kotlin code can be simplified using companion objects, data classes, coroutines and delegates
  • 92. Links Demo Project github.com/fabioCollini/ArchitectureComponentsDemo Libraries AutoValue github.com/google/auto/blob/master/value/userguide/index.md Lightweight Stream github.com/aNNiMON/Lightweight-Stream-API Arrow arrow-kt.io/ Guides and posts Guide to kotlinx.coroutines by example github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md Kotlin coroutines, a deeper look medium.com/@elizarov/kotlin-coroutines-a-deeper-look-180536305c3f 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