Building a Movie App with Kotlin: A Step-by-Step Guide

Mehmet Furkan Eroğlu
LCW Digital
Published in
7 min readMay 2, 2024

Merhaba! Ben Mehmet Furkan, bilgisayar mühendisliği son sınıf öğrencisiyim, LC Waikiki’de stajım boyunca öğrendiklerimi pekiştirmek amacıyla bir proje oluşturup burdaki teknik kısımları açıklayacağım. Bu projede, Kotlin ve Jetpack kütüphanelerini kullanarak geliştirdiğim film ve dizi uygulamamı paylaşmak istiyorum. Bu uygulama, film tutkunlarının filmleri keşfetmelerini, bugün yayınlanacak dizileri öğrenmek ve detaylı bilgilere erişmelerini ve favori filmlerini takip etmelerini kolaylaştıracak şekilde tasarlanmıştır.

Uygulamanın planlanan genel tasarımı

Uygulamanın Özellikleri:

Film ve Dizi Arama: Kullanıcılar, film ve dizi adına, oyunculara, yönetmenlere veya türlere göre içerik araması yapabilir.

Popüler Film ve Yaklaşan Filmlerin Listesi: Kullanıcılar, popüler film ve yaklaşan(upcoming) filmleri liste şeklinde görüp içlerinden hoşuna gideni seçip favorileyebilecek.

Popüler Dizi ve Bugün Çıkan Dizilerin Listesi: Kullanıcılar, popüler dizi ve bugün çıkacak(airing today) dizileri liste halinde görüp hoşuna gideni seçip favorileyebilirler.

Detaylı Film ve Dizi Bilgileri: Her içerik için poster, fragman, özet, oyuncular, yönetmen, türler, puanlar ve kullanıcı yorumları gibi detaylı bilgiler sunulur.

Favoriler Listesi: Kullanıcılar, en sevdikleri filmleri ve dizileri favori listesine ekleyebilir ve daha sonra kolayca erişebilir.

Gelişmiş Kullanıcı Arayüzü: Jetpack kütüphaneleri ile tasarlanmış modern ve kullanımı kolay bir arayüze sahiptir.

Jetpack Kütüphaneleri:

Bu uygulamada, geliştirmeyi kolaylaştırmak ve uygulamanın performansını optimize etmek için Jetpack’ten çeşitli kütüphaneler kullandım:

Data Binding: Kullanıcı arayüzü öğelerini veri modellerine bağlamak için kullanılır.

Hilt: bağımlılıkları yönetmek için kullanılan bir bağımlılık enjeksiyon çerçevesidir. Bağımlılık enjeksiyonu, bir sınıfın diğer sınıflara ihtiyaç duyduğu nesneleri (bağımlılıkları) dışarıdan almalarını sağlayan bir tasarım desenidir. Android’de Dependency Injection kütüphanelerinden biridir.

LiveData: Veri değişikliklerini gözlemlemek ve UI’yi güncellemek için kullanılır.

Navigation: Uygulama içinde farklı ekranlar arasında geçiş yapmak için kullanılır.

ViewModel: Veri ve iş mantığını UI katmanından ayırmak için kullanılır.

Fragment: Modüler ve tekrar kullanılabilir UI bileşenleri oluşturmak için kullanılır.

Firebase: Veritabanı, kimlik doğrulama ve depolama gibi arka uç hizmetleri için kullanılır.

ViewPager2: Yatay kaydırabileceğiniz sayfalar içeren bir kullanıcı arayüzü öğesi oluşturmak için kullanılır.

WebView: Web içeriğini uygulamaya entegre etmek için kullanılır.

Sizde Benimle Birlikte Kendi Movie Uygulamanızı Oluşturabilirsiniz:

Bu yazının sizi kendi Movie Uygulamanızı geliştirmeye teşvik etmesini umuyorum! Kotlin ve Jetpack, modern ve yüksek performanslı Android uygulamaları oluşturmak için güçlü araçlardır. Bu yazılardaki bilgiler ve kod örnekleri, kendi projenizi başlatmanıza yardımcı olacaktır.

Öncelikle ekranlarımızı (UI) yapmaya başlıyoruz.İlk etapta;

  • Onboarding(Tanıtım Ekranları)
  • Splash (Geçiş ve Kontrol Ekranı)

OnBoard Screen

Uygulamalarımız da yine çok önemli bir şekilde kullandığımız tanıtım ekranıdır. Oldukça önemli olup kullanıcıyı applicationla tanıştığı ilk yerdir ve genelde bir defaya mahsus, uygulama ekranların özeti olarak genelde 3'lü geçişli gösterilir.

Splash Screen

Bütün uygulamalar da olmazsa olmaz sayfa olup burada genel olarak application’un config dosyaları , “user data’ları”, token yenileme gibi işlemler burada yapılır. Şimdi gelin UI ekranını çizelim.

fragment_intro.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_color"
tools:context=".view.onBoarding.intro.IntroFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/intro_pic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="0dp"
android:layout_height="100dp"
android:src="@drawable/gradient_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_marginTop="10dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp"
>
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Discovoer Your"
android:textColor="@color/white"
android:textSize="27sp"/>
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Favorite Show"
android:textColor="@color/orange"
android:textSize="27sp"/>
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Watch Now or Watch Later"
android:textSize="27sp"
android:textColor="@color/white"
/>
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="you can browse movies and shows by genre, search for specific title, or check out our reccommendation for you"
android:textSize="17sp"
android:textColor="#9f9a9a"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/getStartedButton"
style="@android:style/Widget.Button"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Get Started"
android:background="@drawable/orange_button_background"
android:textColor="@color/white"
android:textSize="18sp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

Kotlin dilinde XML tasarımı, genellikle Android uygulama geliştirme sürecinde kullanılan bir XML dilidir. Bu XML dosyaları, uygulamanın kullanıcı arayüzünü (UI) tanımlamak için kullanıyoruz.

Android Studio’dan yeni bir proje oluşturduğumuzda her activity’nin bir xml’i de studio tarafından oluşturulur. (MainActivity.kt → activity_main.xml). Ben projemi başlatırken empty views activity’den oluşturdum çünkü activity ile birlikte fragment ve xml dosyalarını da kullanacağım.
Empty Activity: Bu seçenekte, yalnızca bir aktivite dosyası oluşturulur. Bu aktivite dosyası, basit bir kullanıcı arayüzü (UI) içermez. (Empty Activity is now a Composed template.)

  • ConstraintLayout : Android uygulama geliştirme için kullanılan bir layout yöneticisidir. Diğer layout yöneticilerinden farklı olarak, widget’ları esnek bir şekilde konumlandırmanıza ve boyutlandırmanıza olanak tanıyan bir öğedir.
  • ScrollView : İçine yerleştirilen görünüm hiyerarşisinin kaydırılmasına olanak tanıyan bir görünüm grubu.
  • LinearLayout : Diğer görünümleri yatay olarak tek bir sütunda veya dikey olarak tek bir satırda düzenleyen düzen.
  • AppCompatButton : Android uygulamalarında geriye dönük uyumluluk sağlamak için kullanılan bir bileşendir. Bu bileşen, özellikle eski Android sürümlerinde de kulllanılabilen ve modern stil ve özelliklere sahip düğmeler oluşturmanıza olanak tanır.
  • TextView : Kullanıcıya metin görüntüleyen bir kullanıcı arayüzü öğesi.
  • id : Ögeye benzersiz bir kimlik atar. Bu kimlik daha sonra Java veya Kotlin kodunda bu ögeye erişmek için kullanılır.
  • layout_width — layout_height : Ögeye ayrılan dikey ve yatay genişlik.
  • match_parent, bir View'in bir üst View'e olan boyutunu (genişlik veya yükseklik) eşleştirmek için kullanılan bir değerdir. Bir View’in genişliğini veya yüksekliğini match_parent olarak ayarlarsanız, o View, bulunduğu layoutun genişliği veya yüksekliği kadar olacaktır.
  • wrap_content, bir View'in içeriğine uygun boyutlarda olmasını sağlayan bir değerdir. Yani, bir View'in içeriği ne kadar büyükse, o kadar büyük bir alana sahip olur. İçeriğin sığabileceği en küçük alanı kullanır.
fragment_login.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:focusable="true"
android:focusableInTouchMode="true"
android:background="@color/main_color"
tools:context=".view.onBoarding.login.LoginFragment">

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Log In"
android:textSize="50sp"
android:textColor="@color/white"
android:layout_marginTop="128dp"
android:layout_marginStart="32dp"
android:textStyle="bold"/>

<EditText
android:id="@+id/editTextUsername"
android:layout_width="match_parent"
android:layout_height="50sp"
android:ems="10"
android:background="@drawable/edittext_background"
android:inputType="text"
android:textStyle="bold"
android:textAlignment="center"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:layout_marginTop="128dp"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:hint="UserName"/>

<EditText
android:id="@+id/editTextPassword"
android:layout_width="match_parent"
android:layout_height="50sp"
android:layout_marginStart="32dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="32dp"
android:background="@drawable/edittext_background"
android:ems="10"
android:hint="Password"
android:inputType="textPassword"
android:textAlignment="center"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textStyle="bold" />

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textColor="@color/white"
android:textSize="16sp"
android:layout_marginTop="16dp"
android:text="Forgot Your Password?"
android:textStyle="bold"/>

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/loginButton"
style="@android:style/Widget.Button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="32dp"
android:background="@drawable/orange_button_background"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/white"
android:text="Login"/>

<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Don't have an account"
android:textColor="@color/white"
android:textSize="16sp"
android:textAlignment="center"
android:layout_marginTop="32sp"/>

<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Register Now"
android:textColor="@color/white"
android:textSize="16sp"
android:textAlignment="center"
android:textStyle="bold"/>

</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

EditText ve TextView, Android uygulamalarında metin göstermek veya kullanıcıdan metin almak için kullanılan iki farklı bileşendir. Aralarındaki temel farklar şunlardır:

  1. EditText: Kullanıcıdan metin girişi almak için kullanılır. Kullanıcı, EditText bileşenine dokunarak metin girebilir ve bu metin daha sonra uygulama tarafından alınabilir veya kullanılabilir. Örnek kullanım:
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Metin Girin"/>

2. TextView: Metin göstermek için kullanılır, ancak kullanıcı metin giremez. Yani, TextView statik metinleri göstermek için kullanılır ve kullanıcı tarafından değiştirilemez. Örnek kullanım:

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bu bir metin gösterici TextView örneğidir."/>

EditText kullanıcıdan giriş almak için kullanılırken, TextView sadece metin göstermek için kullanılır.

TextViewların birbirine göre durumlarını marginStart, marginEnd, marginTop gibi özellikleri kullanarak sağladım. Farklı bir kullanım çeşiti de parent ile kullanımı vardır.

android:layout_marginStart="32dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="32dp"

XML dosyasında kullandığımız bazı terimlerin anlamları

Başlarken

Uygulamam 2 Activity’den oluşuyor. Bunlardan biri onBoardingActivity diğeri ise MainActivity. onBoardingActivity’i Splash Screen olarak kullandım ve uygulamaya giriş yaptıktan sonra SharedPreferences sayesinde aktif kullanıcı kontrolünü yapıp onBoardingActivity’nin gösterilip gösterilmediğini kontrol ederek aktif kullanıcı varsa bu activityi göstermiyorum ve uygulamam MainActivity’den başlıyor.

val sharedPreferences = getSharedPreferences(Constants.DATABASE_NAME, Context.MODE_PRIVATE)
val hasActiveUser = sharedPreferences.getBoolean(Keys.HAS_ACTIVE_USER, false)

if (hasActiveUser){
startActivity(Intent(this, MainActivity::class.java))
this.finish()
}

OnboardingActivity:

  • Uygulamayı ilk kez açan kullanıcılara gösterilir.
  • Uygulamanın temel işlevleri ve içeriği hakkında kısa bir tanıtım sunar.
  • Birkaç sayfa içerebilir.
  • Kullanıcı, tanıtımı tamamladığında MainActivity’e yönlendirilir.
@AndroidEntryPoint
class OnboardingActivity: AppCompatActivity() {

private lateinit var binding: ActivityOnboardingBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityOnboardingBinding.inflate(layoutInflater)
setContentView(binding.root)

// SharedPreferences'ten onboarding gösterilip gösterilmediğini kontrol et
val sharedPreferences = getSharedPreferences(Constants.DATABASE_NAME, Context.MODE_PRIVATE)
val hasActiveUser = sharedPreferences.getBoolean(Keys.HAS_ACTIVE_USER, false)

if (hasActiveUser){
startActivity(Intent(this, MainActivity::class.java))
this.finish()
}

}
}

MainActivity:

  • Uygulamanın ana ekranıdır.
  • Kullanıcıların filmleri ve dizileri keşfetmelerine, favorilerini takip etmelerine ve diğer kullanıcılara yorum yapmalarına olanak tanır.
  • Farklı sekmelere veya kategorilere ayrılabilir.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
val navController = navHostFragment.navController

setupWithNavController(binding.bottomNavBar,navController)
}
}

private lateinit var binding: ActivityMainBinding ile ; lateinit var, Kotlin dilinde kullanılan bir değişken tanımlama yöntemi olarak kullanıyoruz. Biz burada başlangıçta değeri olmadığı için lateinit tanımlayıp daha sonra onCreate altında değerini veriyoruz.
1. Başlangıç değeri olmayan değişkenler: Bazı durumlarda, bir değişkenin başlangıç değeri olmayabilir, ancak ileride bir noktada bir değer atamak isteyebilirsiniz.
2. Null olmayan değerler: lateinit var kullanarak, değişkenin null olmayacağını garanti edebilirsiniz. Bu nedenle, null değerlerle uğraşmak zorunda kalmazsınız ve null kontrolü yapmanıza gerek kalmaz.

binding , kullanıcı arayüzü bileşenlerini (XML dosyalarında tanımlanan View’ler) Kotlin veya Java koduyla bağlamak için kullanılan bir yöntemdir.

Sizlerle birlikte detaylıca bir uygulamaya giriş yaptık, yapmanız gerekenleri anlattım. Bundan sonra movies ve tvSeries fragmentları, adapter ve recyclerView ekranlarını çizip verileri çekip nasıl yansıtacağımı yazacağım. Part 2'de görüşmek üzere…
Sevgilerimle Mehmet Furkan.

Pika Pika

Kaynak kod için🚀 https://github.com/mehmetfurkaneroglu/MovieApp2024

--

--