SharedViewModel: Activity ve Fragment’lar arası veri paylaşımı

Hanife Kurnaz
4 min readJan 26, 2023

Android geliştirmede, birçok kez verileri fragmentlar ve activityler arasında paylaşmamız gereken bir durumla karşılaşabiliriz. Bu nedenle, verileri activity ve fragmentlar arasında taşımanın birden fazla yolu vardır.

  1. Bundle
  2. Interface
  3. SharedViewModel

Sizlere fragmentlar ve activityler arasında veri taşımanın en basit yöntemi olan SharedViewModel’den bahsedeceğim. Fakat SharedViewModel’den bahsetmeden önce ViewModel nedir ve neden kullanılır bundan bahsedeyim. ViewModel sınıfı, UI ile ilgili verileri yaşam döngüsüne duyarlı bir şekilde depolamak ve yönetmek için tasarlanmıştır. ViewModel her zaman bir scope’la (activity veya fragment) ilişkilendirilerek oluşturulur ve scope canlı olduğu sürece korunur. Örneğin: bir activity ile ilişkilendirildiyse, activity sonlanana kadar ilişkilendirilir. ViewModel’in amacı, bir Activity veya Fragment için gerekli olan bilgileri elde etmek ve saklamaktır. Activity veya Fragment, ViewModel’deki değişiklikleri gözlemleyebilmelidir. ViewModel sınıfları, bu bilgileri genellikle LiveData veya Android Data Binding aracılığıyla gösterir.

Yukarıdaki resimde gördüğümüz gibi, ViewModel’in kendi yaşam süresi vardır. ViewModel nesneleri, ViewModelProvider’a iletildiğinde yaşam döngüsü kapsamına alınır. ViewModel, yaşam döngüsü kapsamı kalıcı olarak kaybolana kadar bellekte kalır.

SharedViewModel Nedir ve Nasıl Kullanılır?

SharedViewModel kullanmanın amacı, Activity ve Fragment arasında veri taşımayı kolaylaştırmaktır. İki fragmenttan oluşan basit bir uygulama geliştireceğiz. Bir fragment, her iki fragmentta kullanılan SharedViewModel nesnesi içindeki verileri güncellerken, diğer fragment bu verilerdeki değişiklikleri gözlemler. Basit bir örnek proje üzerinden nasıl kullanacağımızı öğrenelim.

Öncelikle bir Activity oluşturalım ve aşağıdaki kodları ekleyelim.

class MainActivity : AppCompatActivity() {

private var binding: ActivityMainBinding? = null

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

}

MainActivity sınıfına ait layout dosyasını aşağıdaki şekilde düzenleyelim.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
tools:context=".MainActivity">


<fragment
android:id="@+id/fragment_receiver"
android:name="com.kiliccambaz.sharedviewmodel.MessageReceiverFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="@+id/fragment_sender"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />


<fragment
android:id="@+id/fragment_sender"
android:name="com.kiliccambaz.sharedviewmodel.MessageSenderFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fragment_receiver" />



</androidx.constraintlayout.widget.ConstraintLayout>

Daha sonra SharedViewModel sınıfımızı oluşturalım ve kodları aşağıdaki şekilde düzenleyelim.

class MainSharedViewModel : ViewModel() {

val message = MutableLiveData<String>()

fun sendMessage(text: String) {
message.value = text
}

}

MainSharedViewModel sınıfı içerisinde message adında bir LiveData değişken tanımlanmıştır. LiveData değişken bir verideki değişiklikleri izlememizi sağlayan Observable veri tutucudur.

Şimdi iki tane fragment oluşturalım.

MessageReceiverFragment: Bu Fragment, MessageSenderFragment tarafından gönderilecek mesajı alacak. Alınan mesajı bir TextView’da gösterecektir.

MessageSenderFragment: Bu Fragment, MessageReceiverFragment tarafından alınacak mesajı gönderecektir.

MessageReceiverFragment adında bir fragment oluşturalım ve aşağıdaki kodları ekleyelim.


class MessageReceiverFragment : Fragment() {

private val sharedViewModel: MainSharedViewModel by activityViewModels()
private var binding: FragmentMessageReceiverBinding? = null


override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
)
: View {
binding = FragmentMessageReceiverBinding.inflate(layoutInflater)
return binding!!.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
sharedViewModel.message.observe(viewLifecycleOwner) {
binding!!.tvMessage.text = it
}
}

}

Öncelikle fragment içerisinde MainSharedViewModel sınıfının bir nesnesi oluşturulmaktadır. MainSharedViewModel sınıfı içerisinde yer alan message değişkende oluşan değişiklikleri gözlemlemek için bir observer kullanılmaktadır. Bu observer message değişkenini gözlemleyerek, her değişiklik sonrasında tvMessage isimli TextView güncellenecektir.

Not: activityViewModels(), mevcut activitye ait ViewModel nesnesini verir. Böylece, aynı activitydeki birden çok fragment içerisinde de aynı nesneye erişim gerçekleştirilebilir.

MessageReceiverFragment sınıfına ait layout dosyası:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
tools:context=".MessageReceiverFragment">


<TextView
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.5" />


</androidx.constraintlayout.widget.ConstraintLayout>

MessageSenderFragment adında bir fragment oluşturalım ve aşağıdaki kodları ekleyelim.

class MessageSenderFragment : Fragment() {

private val sharedViewModel: MainSharedViewModel by activityViewModels()
private var binding: FragmentMessageSenderBinding? = null

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
)
: View {
binding = FragmentMessageSenderBinding.inflate(layoutInflater)
return binding!!.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding!!.btnSend.setOnClickListener {
sharedViewModel.sendMessage(binding!!.etMessage.text.toString()) }
}

}

MessageSenderFragment sınıfında butona tıklandığında edittext içerisindeki mesajı MainSharedViewModel içerisinde yer alan message değişkenine atadık.

MessageSenderFragment sınıfına ait layout dosyası:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
tools:context=".MessageSenderFragment">


<EditText
android:id="@+id/et_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:hint="Gönderilecek mesajı giriniz"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</EditText>

<Button
android:id="@+id/btn_send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Gönder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/et_message">
</Button>

</androidx.constraintlayout.widget.ConstraintLayout>

Tüm sınıfları oluşturduktan sonra projeyi çalıştırıp test edebilirsiniz.

Uygulama ekran görüntüsü

Nasıl çalıştığını inceleyelim:

  • İki fragmenttan oluşan bir activity oluşturduk.
  • Her iki fragmentta SharedViewModel nesnesi oluşturduk.
  • MessageSenderFragmentta, butona tıklandığında LiveData message değişkenine bir değer atıyoruz.
  • Ardından MessageReceiverFragmentta LiveData mesajındaki değişikliği gözlemliyoruz ve mesaj geldiğinde TextView’daki veriyi güncelliyoruz.

Bu yazımda, activity ve fragmentlar arası veri taşımak için SharedViewModel’i öğrendik. Umarım yazımı beğenmişsinizdir :)

Sign up to discover human stories that deepen your understanding of the world.

Hanife Kurnaz
Hanife Kurnaz

No responses yet

Write a response