Кotlin Android App Development Course, Creating a News App

Kotlin has established itself as a powerful and modern programming language for Android app development. This course will guide you step-by-step on how to create a real news app using Kotlin. The app is designed to fetch news from an external API and display it to users. Through this article, you will learn about Android application architecture, networking, UI/UX design, and other essential features.

1. Project Setup

The first step of this project is to set up a new project in Android Studio. First, open Android Studio and start a new project.

  • Project Name: NewsApp
  • Package Name: com.example.newsapp
  • Language: Kotlin
  • Device: Phone and Tablet
  • API Level: API 21: Android 5.0 (Lollipop)

Once the project is created, open the AndroidManifest.xml file and add the internet permission as shown below.

<uses-permission android:name="android.permission.INTERNET" />

2. Select News API

Select the API to be used for creating the news app. Here, we will use NewsAPI. It returns results in JSON format and is structured to be easy to use.

To obtain an API key, please sign up on the site and generate an API key.

3. Add Networking Library

We’ll manage network requests using Retrofit from Android Jetpack. Add the Retrofit library to the build.gradle file.

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
}

Sync the Gradle file.

4. Create Data Model Classes

Create data classes to map the data fetched from the news API. Create classes called Article and NewsResponse.

data class Article(
    val source: Source,
    val author: String?,
    val title: String,
    val description: String?,
    val url: String,
    val urlToImage: String?,
    val publishedAt: String,
    val content: String?
)

data class Source(
    val id: String?,
    val name: String
)

data class NewsResponse(
    val status: String,
    val totalResults: Int,
    val articles: List<Article>
)

5. Define Retrofit Interface

Define the Retrofit interface to communicate with NewsAPI. This will allow you to configure HTTP requests.

interface NewsApiService {
    @GET("v2/top-headlines")
    suspend fun getTopHeadlines(
        @Query("country") country: String = "us",
        @Query("apiKey") apiKey: String
    ): NewsResponse
}

6. Create Retrofit Instance

Create a Retrofit instance to prepare for API calls. Use the Singleton pattern to manage the instance.

object RetrofitInstance {
    private const val BASE_URL = "https://newsapi.org"

    private val retrofit by lazy {
        Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl(BASE_URL)
            .build()
    }

    val api: NewsApiService by lazy {
        retrofit.create(NewsApiService::class.java)
    }
}

7. Utilize ViewModel and LiveData

To apply the MVVM pattern, use ViewModel and LiveData to separate the UI from the data. Create a ViewModel to manage the news data.

class NewsViewModel(private val apiKey: String) : ViewModel() {
    private val _news = MutableLiveData<List<Article>>()
    val news: LiveData<List<Article>> get() = _news

    fun fetchTopHeadlines() {
        viewModelScope.launch {
            val response = RetrofitInstance.api.getTopHeadlines(apiKey = apiKey)
            _news.postValue(response.articles)
        }
    }
}

8. Design UI

Modify the layout file of MainActivity to add a RecyclerView. Below is an example of activity_main.xml.

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:listitem="@layout/item_article"/>

Create a layout item_article.xml to display each news item.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:scaleType="centerCrop"/>

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:padding="8dp"/>

    <TextView
        android:id="@+id/descriptionTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:padding="8dp"/>

</LinearLayout>

9. Configure RecyclerView Adapter

Implement RecyclerView.Adapter to display news data on the screen.

class NewsAdapter(private val articles: List<Article>) : RecyclerView.Adapter<NewsAdapter.NewsViewHolder>() {

    inner class NewsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val titleTextView: TextView = itemView.findViewById(R.id.titleTextView)
        val descriptionTextView: TextView = itemView.findViewById(R.id.descriptionTextView)
        val imageView: ImageView = itemView.findViewById(R.id.imageView)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_article, parent, false)
        return NewsViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
        val currentArticle = articles[position]
        holder.titleTextView.text = currentArticle.title
        holder.descriptionTextView.text = currentArticle.description
        // Image loading is handled by libraries like Glide or Picasso
    }

    override fun getItemCount() = articles.size
}

10. Data Binding in MainActivity

Set up the RecyclerView in MainActivity and fetch data through the ViewModel.

class MainActivity : AppCompatActivity() {
    private lateinit var newsViewModel: NewsViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this)

        val apiKey = "YOUR_API_KEY" // Enter your API key
        newsViewModel = ViewModelProvider(this, ViewModelFactory(apiKey)).get(NewsViewModel::class.java)

        newsViewModel.fetchTopHeadlines()
        newsViewModel.news.observe(this, { articles ->
            val adapter = NewsAdapter(articles)
            recyclerView.adapter = adapter
        })
    }
}

11. Improve User Interface

Add click events to each news item so that users can navigate to the article’s URL when they click on it.

class NewsAdapter(private val articles: List<Article>, private val context: Context) : RecyclerView.Adapter<NewsAdapter.NewsViewHolder>() {
    inner class NewsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val titleTextView: TextView = itemView.findViewById(R.id.titleTextView)
        val descriptionTextView: TextView = itemView.findViewById(R.id.descriptionTextView)
        val imageView: ImageView = itemView.findViewById(R.id.imageView)

        init {
            itemView.setOnClickListener {
                val position: Int = adapterPosition
                val article = articles[position]
                val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(article.url))
                context.startActivity(browserIntent)
            }
        }
    }
}

12. Changing User Experience

Add a ProgressBar to improve the app’s user experience, informing users about the loading progress when retrieving data.

<ProgressBar
    android:id="@+id/progressBar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"/>

Modify the MainActivity code to show the ProgressBar during data loading and hide it when loading is complete.

newsViewModel.news.observe(this, { articles ->
    progressBar.visibility = View.GONE
    recyclerView.adapter = NewsAdapter(articles, this)
})

// Show ProgressBar before data loading
progressBar.visibility = View.VISIBLE

Summary and Conclusion

In this course, we explored the entire process of creating a news app using Kotlin. You had the opportunity to learn essential to advanced techniques needed for real app development, including setting up Retrofit for network communication, managing data with the MVVM architecture, and using RecyclerView. Additionally, you can improve the design or extend features to provide a better user experience.

You are now ready to create your own news app! Practice it yourself and try adding various features.