11 mins
Apr 03, 2024
At Google I/O 2017, the Android team had announced remarkable support for Kotlin, the statically typed programming language for the JVM (Java Virtual Machine).
In fact, Kotlin has already become a buzz in the Android development for years, and the number of projects developed using Kotlin is consistently increasing at Github as well. However, this language was always in a very awkward position for Android developers because it had never been supported officially. But now, the status quo has changed.
Thought Kotlin has been declared official Android language, existing languages have also been empowered in the best possible way. For example:
class UserEntity { var userId: String? = null var name: String? = null var email: String? = null var mobileNumber: String? = null }
When we develop the application using Java, most of our code is defensive. We need to keep checking continuously if something is null before we use it. Otherwise we may find unexpected NullPointerException. Kotlin, as many other languages, is null safe because we need to explicitly specify if an object can be null by using the safe call operator.
We can do things like this:
var a: String = “abc” a = null // compilation errorvar b: String? = “abc” b = null // ok
if (b != null && b.length > 0) { print(“String of length ${b.length}”) } else { print(“Empty string”) }
b?.length
Extension functions
We can add new functions to any class. It´s a much more readable substitute to the typical utility classes we all have in our projects. We could, for instance, add a new method to fragments to show a toast:
fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) { Toast.makeText(getActivity(), message, duration).show() }
fragment.toast(“Hello world!”)
What if instead of having to write the creation of a new listener every time we need to declare what a click should do, we could just define what we want to do? We can indeed. This (and many more interesting things) is what we get thanks to lambda usage:
view.setOnClickListener { toast(“Hello world!”) }
As a part of our exploration about how Kotlin actually works with the real world application, below are the Kotlin specimen codes we have created for our Hello World News application. The objective is to fetch data from server to mobile device and getting it displayed to UI in the desired format using Kotlin. The specimen codes are described in three different stages:
// Get the list of data from server private fun getNewsList() { //Create retrofit Service var mNewsService: NewsService = ApiProduction(this).provideService(NewsService::class.java) //List of source: https://newsapi.org/sources //List of sort by option: https://newsapi.org/#apiArticles var apiCall: Observable<NewsListResponse> = mNewsService.getNewsApi(“techcrunch”, “top”, getString(R.string.new_api_key) //Test API Key ) RxAPICallHelper().call(apiCall, object : RxAPICallback<NewsListResponse> { override fun onSuccess(newsItems: NewsListResponse) { //status= “error” in case of error if (newsItems.getStatus().equals(“ok”)) { setNewsData(newsItems) } } override fun onFailed(throwable: Throwable) { } }) }
// Update data on UI private fun setNewsData(newsItems: NewsListResponse) { recyclerNews.layoutManager = LinearLayoutManager(this) val newsRecyclerAdapter: NewsRecyclerAdapter = NewsRecyclerAdapter() newsRecyclerAdapter.setData(newsItems.getArticles() as ArrayList<NewsListResponse.Article>) recyclerNews.adapter = newsRecyclerAdapter newsRecyclerAdapter.setOnItemClick(object : NewsRecyclerAdapter.MyAdapterListener { override fun onItemViewClick(mUrl:String,position: Int) { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse( mUrl))) } }) }
// How to render data using Recycler Adapter
class NewsRecyclerAdapter : RecyclerView.Adapter<NewsRecyclerAdapter.TaskViewHolder>() { lateinit var tasks: ArrayList<NewsListResponse.Article> lateinit var mItemClickListener: MyAdapterListener override fun onCreateViewHolder(parent: android.view.ViewGroup, type: Int): TaskViewHolder { return TaskViewHolder(parent) } fun setData(tasks: ArrayList<NewsListResponse.Article>) { this.tasks = tasks notifyDataSetChanged() } fun addTodo(todoTask: NewsListResponse.Article) { this.tasks.add(todoTask) notifyItemChanged(tasks.size) } override fun onBindViewHolder(viewHolder: NewsRecyclerAdapter.TaskViewHolder, position: Int) { viewHolder.bind(tasks[position], position) } override fun getItemCount(): Int = tasks.size inner class TaskViewHolder(parent: android.view.ViewGroup) : RecyclerView.ViewHolder(android.view.LayoutInflater.from(parent.context). inflate(R.layout.list_item_news, parent, false)) { fun bind(task: NewsListResponse.Article, position: Int): Unit = with(itemView) { tvListItemAuthor.text=task.author tvListItemDateTime.text=task.publishedAt tvListItemTitle.text=task.title itemView.setOnClickListener({ task.url?.let { mUrl -> mItemClickListener.onItemViewClick(mUrl,position) } }) Glide.with(itemView.context) .load(task.urlToImage) .into(ivListItem) var df: DateFormat = SimpleDateFormat(“yyyy-MM-dd’T’HH:mm:ss”, Locale.getDefault()) val d = df.parse(task.publishedAt) df = SimpleDateFormat(“dd MMM,yyyy hh:mm a”, Locale.getDefault()) tvListItemDateTime.text=df.format(d) } } fun setOnItemClick(itemClickListener: MyAdapterListener): Unit { this.mItemClickListener = itemClickListener } interface MyAdapterListener { fun onItemViewClick(webUrl:String,position: Int)