Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Development Workshop

Android Development Workshop

This is a workshop that i gave to at the University of Johannesburg in 2018.
In 2019 I did a similar workshop, but the project we built was an API with Ktor.

https://github.com/pjwelcome/Ktor-StarterProject
https://github.com/pjwelcome/AndroidWorkshop

Peter-John Welcome

July 15, 2019
Tweet

More Decks by Peter-John Welcome

Other Decks in Programming

Transcript

  1. What we will do Today: Intro: 1. Create our first

    Android app and run it. 2. Git Crash Course 3. Learn Kotlin for Android 4. Crash Course on Android Layouts. (Constraint Layouts) 5. RecyclerViews (View Holder Pattern)
  2. Android Dependencies dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support:recyclerview-v7:27.1.1' }
  3. What is git? • Git is an example of a

    DVCS (hence Distributed Version Control System)
  4. Why Kotlin over Java? • Java is very verbose. •

    Java Code is error prone with all its anonymous inner classes. • Java lacks modern language features. • Nullability issues.
  5. var/val var name : String = "Peter" name = "John"

    val surname = "Welcome" surname = "Johnson" // val can’t be reassigned
  6. Nullability var name : String = "Peter" name = null

    // null can’t be a value on a non-null String var surname : String? = "Peter" surname = null val otherName = surname ?: "" // Elvis operator ( ?? in other languages)
  7. Classes class User { private val name: String private val

    surname : String constructor(name : String , surname: String) { this .name = name this.surname = surname } } var user = User( surname = "Welcome", name = "Peter") // named arguments
  8. Data class @Parcelize data class Human (private var name: String,

    val age: Int) : Parcelable //copy, equal, hashcode, toString var human = Human("Peter",27)
  9. Sealed Classes sealed class Result<out T>{ data class Success<out T>

    (val value : T) : Result<T>() data class Error(val error : MyError) : Result<MyError>() }
  10. Sealed Classes fun <T>resultsFromService(result : Result<T>) : String { when

    (result) { is Result.Success -> "${result.value} World" is Result.Error -> return result.error.toString() } return "" } resultsFromService(Result.Success("Hello"))
  11. Functions fun hello(){ print("Hello") } val functionAsVariable = hello() val

    greetingPeter = fun (func : (name :String) -> String ) : String = func("Peter") greetingPeter { "Hello $it" }
  12. Extension functions infix fun Int.add (value : Int) = this

    + value val result = 1.add(1) val result = 1 add 1 //Extension function fun <T> Observable<T>.applySchedulers() : Observable<T> = this.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) //Usage disposable.add(this.viewModel.createPlant(Plant(name = "Best Plant Ever")).applySchedulers().subscribe ())
  13. Function Literals with Receiver inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit)

    { val editor = edit() editor.action() editor.apply() } getSharedPreferences("cache", Context.MODE_PRIVATE).edit { putString("username", "Peter") }
  14. AsyncTasks class doAsyncTask(textView: TextView) : AsyncTask<Unit, Unit, String>() { val

    innerTextView: TextView? = textView override fun doInBackground(vararg params: Unit?): String? { try { ... return data } catch (e: Exception) { return null } } override fun onPostExecute(result: String?) { super.onPostExecute(result) innerTextView?.text = JSONObject(result).toString() } }
  15. RxJava disposable.add(viewModel.fetchDashboardPlants() .applySchedulers() .subscribe({ //onNext: ... }, { error ->

    //onError }) ) fun <T> Observable<T>.applySchedulers() : Observable<T> = this.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
  16. Coroutines internal val background = newFixedThreadPoolContext(2, "background") launch (background) {

    val result = resultsFromService(Result.Success("Hello")) launch(UI) { this.textView.text = result } } // The async await way val someLongRunningTask = async<String>(CommonPool) { return@async "" }.await()
  17. RecyclerView <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_animal_type" android:layout_width="wrap_content"

    android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="48dp" android:layout_marginEnd="16dp" android:text="animal name" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
  18. RecyclerView class AnimalAdapter(val items: ArrayList<String>) : RecyclerView.Adapter<ViewHolder>() { // Gets

    the number of animals in the list override fun getItemCount(): Int { return items.size } // Inflates the item views override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.animal_list_item, parent, false)) } // Binds each animal in the ArrayList to a view override fun onBindViewHolder(holder: ViewHolder, position: Int) { holder.tvAnimalType.text = items.get(position) } } class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { // Holds the TextView that will add each animal to val tvAnimalType = view.tv_animal_type }