Android development with Kotlin (2)
14.2.3 Implement back-end API access
In this section, we will implement the logic of backend API access and data display.
Create a new domain object class Movie
data class Movie(val id: String, val title: String, val overview: String, val posterPath: String) {
override fun toString(): String {
return "Movie(id='$id', title='$title', overview='$overview', posterPath='$posterPath')"
}
}
copy
The data structure and analysis returned by the API
The API we call is
val VOTE_AVERAGE_API = "http://api.themoviedb.org//3/discover/movie?certification_country=US&certification=R&sort_by=vote_average.desc&api_key=7e55a88ece9f03408b895a96c1487979"
copy
Its data return is
{
"page": 1,
"total_results": 10350,
"total_pages": 518,
"results": [
{
"vote_count": 28,
"id": 138878,
"video": false,
"vote_average": 10,
"title": "Fatal Mission",
"popularity": 3.721883,
"poster_path": "/u351Rsqu5nd36ZpbWxIpd3CpbJW.jpg",
"original_language": "en",
"original_title": "Fatal Mission",
"genre_ids": [
10752,
28,
12
],
"backdrop_path": "/wNq5uqVDT7a5G1b97ffYf4hxzYz.jpg",
"adult": false,
"overview": "A CIA Agent must rely on reluctant help from a female spy in the North Vietnam jungle in order to pass through enemy lines.",
"release_date": "1990-07-25"
},
...
]
}
copy
We use fastjson to parse this data. Add dependencies in build.gradle under app
dependencies {
...
// https://mvnrepository.com/artifact/com.alibaba/fastjson
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.39'
}
copy
The parsing code is as follows
val jsonstr = URL(VOTE_AVERAGE_API).readText(Charset.defaultCharset())
try {
val obj = JSON.parse(jsonstr) as Map<*, *>
val dataArray = obj.get("results") as JSONArray
}
} catch (ex: Exception) {
}
copy
Then we put this dataArray into our MovieContent object
dataArray.forEachIndexed { index, it ->
val title = (it as Map<*, *>).get("title") as String
val overview = it.get("overview") as String
val poster_path = it.get("poster_path") as String
addMovie(Movie(index.toString(), title, overview, getPosterUrl(poster_path)))
}
copy
where the code for addMovie is
object MovieContent {
val MOVIES: MutableList<Movie> = ArrayList()
val MOVIE_MAP: MutableMap<String, Movie> = HashMap()
...
private fun addMovie(movie: Movie) {
MOVIES.add(movie)
MOVIE_MAP.put(movie.id, movie)
}
}
copy
Then, we create MovieDetailActivity, MovieDetailFragment, MovieListActivity and activity_movie_list.xml, activity_movie_detail.xml, movie_detail.xml, movie_list.xml, movie_list_content.xml, and their codes are introduced as follows.
Movie List Page
MovieListActivity is the Activity of the movie list page, the code is as follows
package com.easy.kotlin
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.easy.kotlin.bean.MovieContent
import com.easy.kotlin.util.HttpUtil
import kotlinx.android.synthetic.main.activity_movie_detail.*
import kotlinx.android.synthetic.main.activity_movie_list.*
import kotlinx.android.synthetic.main.movie_list.*
import kotlinx.android.synthetic.main.movie_list_content.view.*
class MovieListActivity : AppCompatActivity() {
private var mTwoPane: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie_list)
setSupportActionBar(toolbar)
toolbar.title = title
if (movie_detail_container != null) {
mTwoPane = true
}
setupRecyclerView(movie_list)
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
recyclerView.adapter = SimpleItemRecyclerViewAdapter(this, MovieContent.MOVIES, mTwoPane)
}
class SimpleItemRecyclerViewAdapter(private val mParentActivity: MovieListActivity,
private val mValues: List<MovieContent.Movie>,
private val mTwoPane: Boolean) : RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder>() {
private val mOnClickListener: View.OnClickListener
init {
mOnClickListener = View.OnClickListener { v ->
val item = v.tag as MovieContent.Movie
if (mTwoPane) {
val fragment = MovieDetailFragment().apply {
arguments = Bundle()
arguments.putString(MovieDetailFragment.ARG_MOVIE_ID, item.id)
}
mParentActivity.supportFragmentManager
.beginTransaction()
.replace(R.id.movie_detail_container, fragment)
.commit()
} else {
val intent = Intent(v.context, MovieDetailActivity::class.java).apply {
putExtra(MovieDetailFragment.ARG_MOVIE_ID, item.id)
}
v.context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater
.from(parent.context)
.inflate(R.layout.movie_list_content, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = mValues[position]
holder.mIdView.text = item.id
holder.mTitle.text = item.title
holder.mMoviePosterImageView.setImageBitmap(HttpUtil.getBitmapFromURL(item.posterPath))
with(holder.itemView) {
tag = item
setOnClickListener(mOnClickListener)
}
}
override fun getItemCount(): Int {
return mValues.size
}
inner class ViewHolder(mView: View) : RecyclerView.ViewHolder(mView) {
val mIdView: TextView = mView.id_text
val mTitle: TextView = mView.title
val mMoviePosterImageView: ImageView = mView.movie_poster_image
}
}
}
copy
The corresponding layout file is as follows
activity_movie_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context="com.easy.kotlin.MovieListActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<include layout="@layout/movie_list" />
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
copy
movie_list.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView 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:id="@+id/movie_list"
android:name="com.easy.kotlin.MovieListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context="com.easy.kotlin.MovieListActivity"
tools:listitem="@layout/movie_list_content" />
copy
movie_list_content.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="320dp"
android:layout_gravity="center"
android:layout_margin="0dp"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:orientation="horizontal">
<TextView
android:id="@+id/id_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<ImageView
android:id="@+id/movie_poster_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<View
android:id="@+id/title_background"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:alpha="0.8"
android:background="@color/colorPrimaryDark"
android:gravity="center" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:gravity="center"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:textColor="@android:color/white"
android:textSize="12sp" />
</FrameLayout>
copy
The UI of the overall layout of the movie list is shown in the figure below
The UI of the overall layout of the movie list
View Data Adapter ViewAdapter
We need to display the response data in the process of creating MovieListActivity. These data are carried by ViewAdapter. The corresponding code is as follows
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie_list)
setSupportActionBar(toolbar)
toolbar.title = title
if (movie_detail_container != null) {
mTwoPane = true
}
setupRecyclerView(movie_list)
}
private fun setupRecyclerView(recyclerView: RecyclerView) {
recyclerView.adapter = SimpleItemRecyclerViewAdapter(this, MovieContent.MOVIES, mTwoPane)
}
copy
In the above code, we define a SimpleItemRecyclerViewAdapter class that inherits RecyclerView.Adapter to load the data to be displayed in the View and realize the decoupling of the data and the view. The data to be displayed by the View is obtained from the Adapter and displayed. The Adapter is responsible for matching the real data into Views, that is to say, what data the View displays depends on the data in the Adapter.
Display of images in views
Among them, in the function SimpleItemRecyclerViewAdapter.onBindViewHolder, we set the binding between the View component and the Model data. The movie posters are pictures, so we use ImageView in our layout file, and the corresponding layout file is movie_list_content.xml, the code is as follows
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="320dp"
android:layout_gravity="center"
android:layout_margin="0dp"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:orientation="horizontal">
<TextView
android:id="@+id/id_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<ImageView
android:id="@+id/movie_poster_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
<View
android:id="@+id/title_background"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:alpha="0.8"
android:background="@color/colorPrimaryDark"
android:gravity="center" />
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom"
android:gravity="center"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:textColor="@android:color/white"
android:textSize="12sp" />
</FrameLayout>
copy
UI design renderings
MovieListActivity layout UI
Display of pictures in the list
The view component about the picture is ImageView
<ImageView
android:id="@+id/movie_poster_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop" />
copy
Here we display pictures according to the URL of the picture. The ImageView class has a setImageBitmap method, which can directly set the Bitmap picture data
holder.mMoviePosterImageView.setImageBitmap(HttpUtil.getBitmapFromURL(item.posterPath))
copy
And the code to get Bitmap image data through url is
object HttpUtil {
fun getBitmapFromURL(src: String): Bitmap? {
try {
val url = URL(src)
val input = url.openStream()
val myBitmap = BitmapFactory.decodeStream(input)
return myBitmap
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
}
copy
Movie Details Page
MovieDetailActivity is the movie details page, the code is as follows
package com.easy.kotlin
import android.content.Intent
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
import kotlinx.android.synthetic.main.activity_movie_detail.*
class MovieDetailActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_movie_detail)
setSupportActionBar(detail_toolbar)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own detail action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (savedInstanceState == null) {
val arguments = Bundle()
arguments.putString(MovieDetailFragment.ARG_MOVIE_ID,
intent.getStringExtra(MovieDetailFragment.ARG_MOVIE_ID))
val fragment = MovieDetailFragment()
fragment.arguments = arguments
supportFragmentManager.beginTransaction()
.add(R.id.movie_detail_container, fragment)
.commit()
}
}
override fun onOptionsItemSelected(item: MenuItem) =
when (item.itemId) {
android.R.id.home -> {
navigateUpTo(Intent(this, MovieListActivity::class.java))
true
}
else -> super.onOptionsItemSelected(item)
}
}
copy
The layout XML file of the details page is activity_item_detail.xml, and the code is as follows
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context="com.easy.kotlin.ItemDetailActivity"
tools:ignore="MergeRootFrame">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/app_bar_height"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@+id/toolbar">
<android.support.v7.widget.Toolbar
android:id="@+id/detail_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/item_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_margin="@dimen/fab_margin"
app:layout_anchor="@+id/item_detail_container"
app:layout_anchorGravity="top|end"
app:srcCompat="@android:drawable/stat_notify_chat" />
</android.support.design.widget.CoordinatorLayout>
copy
We put the Fragment display of movie details in NestedScrollView
<android.support.v4.widget.NestedScrollView
android:id="@+id/movie_detail_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
copy
The Fragment code for movie details is MovieDetailFragment
package com.easy.kotlin
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.easy.kotlin.bean.MovieContent
import com.easy.kotlin.util.HttpUtil
import kotlinx.android.synthetic.main.activity_movie_detail.*
import kotlinx.android.synthetic.main.movie_detail.view.*
class MovieDetailFragment : Fragment() {
private var mItem: MovieContent.Movie? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (arguments.containsKey(ARG_MOVIE_ID)) {
mItem = MovieContent.MOVIE_MAP[arguments.getString(ARG_MOVIE_ID)]
mItem?.let {
activity.toolbar_layout?.title = it.title
}
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// 绑定 movieDetailView
val movieDetailView = inflater.inflate(R.layout.movie_detail, container, false)
mItem?.let {
movieDetailView.movie_poster_image.setImageBitmap(HttpUtil.getBitmapFromURL(it.posterPath))
movieDetailView.movie_overview.text = "影片简介: ${it.overview}"
movieDetailView.movie_vote_count.text = "打分次数:${it.vote_count}"
movieDetailView.movie_vote_average.text = "评分:${it.vote_average}"
movieDetailView.movie_release_date.text = "发行日期:${it.release_date}"
}
return movieDetailView
}
companion object {
const val ARG_MOVIE_ID = "movie_id"
}
}
copy
The R.layout.movie_detail layout file movie_detail.xml is as follows
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="0dp"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:orientation="vertical">
<TextView
android:id="@+id/movie_release_date"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textIsSelectable="true"
android:textSize="18sp"
tools:context="com.easy.kotlin.MovieDetailFragment" />
<ImageView
android:id="@+id/movie_poster_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:fitsSystemWindows="true"
android:scaleType="fitCenter" />
<TextView
android:id="@+id/movie_overview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textIsSelectable="true"
android:textSize="18sp"
tools:context="com.easy.kotlin.MovieDetailFragment" />
<TextView
android:id="@+id/movie_vote_average"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textIsSelectable="true"
android:textSize="18sp"
tools:context="com.easy.kotlin.MovieDetailFragment" />
<TextView
android:id="@+id/movie_vote_count"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:textIsSelectable="true"
android:textSize="18sp"
tools:context="com.easy.kotlin.MovieDetailFragment" />
</LinearLayout>
copy
Acquisition of movie source data
We define a MovieContent object class to store the data obtained from the API, the code is as follows
package com.easy.kotlin.bean
import android.os.StrictMode
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import java.net.URL
import java.nio.charset.Charset
import java.util.*
object MovieContent {
val MOVIES: MutableList<Movie> = ArrayList()
val MOVIE_MAP: MutableMap<String, Movie> = HashMap()
val VOTE_AVERAGE_API = "http://api.themoviedb.org//3/discover/movie?sort_by=popularity.desc&api_key=7e55a88ece9f03408b895a96c1487979&page=1"
init {
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
initMovieListData()
}
private fun initMovieListData() {
val jsonstr = URL(VOTE_AVERAGE_API).readText(Charset.defaultCharset())
try {
val obj = JSON.parse(jsonstr) as Map<*, *>
val dataArray = obj.get("results") as JSONArray
dataArray.forEachIndexed { index, it ->
val title = (it as Map<*, *>).get("title") as String
val overview = it.get("overview") as String
val poster_path = it.get("poster_path") as String
val vote_count = it.get("vote_count").toString()
val vote_average = it.get("vote_average").toString()
val release_date = it.get("release_date").toString()
addMovie(Movie(id = index.toString(),
title = title,
overview = overview,
vote_count = vote_count,
vote_average = vote_average,
release_date = release_date,
posterPath = getPosterUrl(poster_path)))
}
} catch (ex: Exception) {
ex.printStackTrace()
}
}
private fun addMovie(movie: Movie) {
MOVIES.add(movie)
MOVIE_MAP.put(movie.id, movie)
}
fun getPosterUrl(posterPath: String): String {
return "https://image.tmdb.org/t/p/w185_and_h278_bestv2$posterPath"
}
data class Movie(val id: String,
val title: String,
val overview: String,
val vote_count: String,
val vote_average: String,
val release_date: String,
val posterPath: String)
}
copy
The default thread mode after Android 4.0 is not to allow access to the network in the main thread. In order to demonstrate the effect, we set ThreadPolicy to allow access to the network before accessing the network code
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
copy
We use a data class Movie to store movie object data
data class Movie(val id: String,
val title: String,
val overview: String,
val vote_count: String,
val vote_average: String,
val release_date: String,
val posterPath: String)
copy
Configure AndroidManifest.xml
Finally, we configure the contents of the AndroidManifest.xml file as follows
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.easy.kotlin">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
<activity
android:name=".MovieListActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MovieDetailActivity"
android:label="@string/title_movie_detail"
android:parentActivityName=".MovieListActivity"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.easy.kotlin.MovieListActivity" />
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
Because we want to access the network, we need to add this line of configuration
<uses-permission android:name="android.permission.INTERNET" />
copy
Package, install and run again, the effect picture is as follows
Movie List Page
Movie List Page
Click to enter the movie details page
Movie Details Page
chapter summary
Null references that often appear in Android, redundant boilerplate code in APIs, etc. are all driving forces for us to switch to the Kotlin language. In addition, Kotlin's Android view DSL Anko can free us from complicated XML view configuration files. We can use popular libraries developed by Android such as Butter Knife, Realm, RecyclerView, etc. as conveniently as in Java. Of course, we use Kotlin to integrate these libraries for Android development, which can not only directly use our previous development libraries, but also get out of the limitations of the Java language and Android API. This has to be said to be a good thing.
at last
More Kotlin learning materials can be scanned for free!
" Advanced Kotlin Enhanced Combat "
Chapter 1 Kotlin Getting Started Tutorial
● Kotlin overview
● Kotlin vs. Java
● Skillful use of Android Studio
● Understand the basic types of Kotlin
● Walk into Kotlin's array
● Walk into Kotlin collections
● Complete code
● Basic grammar
Chapter 2 Kotlin Practical Pit Avoidance Guide
● Method input parameters are constants and cannot be modified
● No Companion, INSTANCE?
● Java overloading, how to make a clever transition in Kotlin?
● Null gesture in Kotlin
● Kotlin overrides the method in the Java parent class
● Kotlin becomes "ruthless", even TODO is not spared!
● Pitfalls in is and as`
● Understanding of Property in Kotlin
● also keyword
● takeIf keyword
● How to write singleton mode
Chapter 3 Project Combat "Kotlin Jetpack Combat"
● Start with a demo that worships a great god
● What is the experience of writing Gradle scripts in Kotlin?
● The Triple Realm of Kotlin Programming
● Kotlin higher order functions
● Kotlin Generics
● Kotlin Extensions
● Kotlin delegates
● Coroutine "unknown" debugging skills
● Graphical coroutine: suspend
" The most detailed Android version of kotlin coroutine entry advanced combat in history "
Chapter 1 Introduction to the Basics of Kotlin Coroutines
● What is a coroutine
● What is Job, Deferred, and coroutine scope
● Basic usage of Kotlin coroutines
Chapter 2 Preliminary Explanation of Key Knowledge Points of Kotlin Coroutine
● Coroutine Scheduler
● Coroutine context
● Coroutine startup mode
● Coroutine scope
● suspend function
Chapter 3 Exception Handling of Kotlin Coroutines
● Generation process of coroutine exception
● Exception handling for coroutines
Chapter 4 Basic application of kotlin coroutines in Android
● Android uses kotlin coroutines
● Use coroutines in Activity and Framgent
● Use coroutines in ViewModel
● Use coroutines in other environments