Yaşam Döngüsü Bilinçli Bileşenlerle Yaşam Döngülerini İşleme   Android Jetpack'in bir parçasıdır.

Yaşam döngüsü bilincine sahip bileşenler, etkinlikler ve parçalar gibi başka bir bileşenin yaşam döngüsü durumundaki bir değişikliğe yanıt olarak işlemler gerçekleştirir. Bu bileşenler, daha iyi düzenlenmiş ve genellikle daha hafif, bakımı daha kolay kodlar oluşturmanıza yardımcı olur.

Bağımsız bileşenlerin işlemlerini, etkinliklerin ve parçaların yaşam döngüsü yöntemlerinde uygulamak yaygın bir yöntemdir. Ancak bu kalıp, kodun kötü bir şekilde düzenlenmesine ve hataların çoğalmasına yol açar. Yaşam döngüsüne duyarlı bileşenleri kullanarak, bağımlı bileşenlerin kodunu yaşam döngüsü yöntemlerinden bileşenlerin içine taşıyabilirsiniz.

androidx.lifecycle paketi, yaşam döngüsü bilincine sahip bileşenler oluşturmanıza olanak tanıyan sınıflar ve arayüzler sağlar. Bu bileşenler, davranışlarını bir etkinliğin veya parçanın mevcut yaşam döngüsü durumuna göre otomatik olarak ayarlayabilir.

Android Framework'da tanımlanan uygulama bileşenlerinin çoğuna yaşam döngüsü eklenmiştir. Yaşam döngüleri, işletim sistemi veya işleminizde çalışan çerçeve kodu tarafından yönetilir. Bu politikalar, Android'in işleyiş şeklinin temelini oluşturur ve uygulamanız bu politikalara uymalıdır. Aksi takdirde bellek sızıntısı veya hatta uygulama kilitlenmesi tetiklenebilir.

Ekranda cihaz konumunu gösteren bir etkinliğimiz olduğunu varsayalım. Sık kullanılan bir uygulama aşağıdaki gibi olabilir:

Kotlin

internal class MyLocationListener(
        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start() {
        // connect to system location service
    }

    fun stop() {
        // disconnect from system location service
    }
}

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        myLocationListener.start()
        // manage other components that need to respond
        // to the activity lifecycle
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

Java

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // connect to system location service
    }

    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

Bu örnek iyi görünse de gerçek bir uygulamada, yaşam döngüsünün mevcut durumuna yanıt olarak kullanıcı arayüzünü ve diğer bileşenleri yöneten çok fazla çağrınız olur. Birden fazla bileşeni yönetmek, onStart() ve onStop() gibi yaşam döngüsü yöntemlerine önemli miktarda kod yerleştirir. Bu da bu yöntemlerin bakımını zorlaştırır.

Ayrıca, bileşenin etkinlik veya parça durdurulmadan önce başlayacağı garanti edilmez. Bu durum özellikle onStart()'te bazı yapılandırma kontrolleri gibi uzun süren bir işlem gerçekleştirmemiz gerektiğinde geçerlidir. Bu, onStop() yönteminin onStart() yönteminden önce tamamlandığı ve bileşenin gerektiğinden daha uzun süre etkin kaldığı bir yarış durumuna neden olabilir.

Kotlin

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        Util.checkUserStatus { result ->
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
    }

}

Java

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}

androidx.lifecycle paketi, bu sorunları esnek ve izole bir şekilde ele almanıza yardımcı olan sınıflar ve arayüzler sağlar.

Yaşam döngüsü

Lifecycle, bir bileşenin (ör. etkinlik veya parça) yaşam döngüsü durumuyla ilgili bilgileri barındıran ve diğer nesnelerin bu durumu gözlemlemesine olanak tanıyan bir sınıftır.

Lifecycle, ilişkili bileşeninin yaşam döngüsü durumunu izlemek için iki ana numaralandırma kullanır:

Etkinlik
Çerçeveden ve Lifecycle sınıfından gönderilen yaşam döngüsü etkinlikleri. Bu etkinlikler, etkinlikler ve parçalardaki geri çağırma etkinlikleriyle eşlenir.
Eyalet
Lifecycle nesnesi tarafından izlenen bileşenin mevcut durumu.
Yaşam döngüsü durumlarının şeması
Şekil 1. Android etkinlik yaşam döngüsünü oluşturan durumlar ve olaylar

Durumları bir grafiğin düğümleri, etkinlikleri ise bu düğümler arasındaki kenarlar olarak düşünün.

Bir sınıf, DefaultLifecycleObserver sınıfını uygulayarak ve onCreate, onStart gibi ilgili yöntemleri geçersiz kılarak bileşenin yaşam döngüsü durumunu izleyebilir. Ardından, aşağıdaki örnekte gösterildiği gibi Lifecycle sınıfının addObserver() yöntemini çağırıp gözlemcinizin bir örneğini ileterek bir gözlemci ekleyebilirsiniz:

Kotlin

class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        connect()
    }

    override fun onPause(owner: LifecycleOwner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

Java

public class MyObserver implements DefaultLifecycleObserver {
    @Override
    public void onResume(LifecycleOwner owner) {
        connect()
    }

    @Override
    public void onPause(LifecycleOwner owner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

Yukarıdaki örnekte myLifecycleOwner nesnesi, aşağıdaki bölümde açıklanan LifecycleOwner arayüzünü uygular.

LifecycleOwner

LifecycleOwner, sınıfın Lifecycle olduğunu belirten tek yöntemli bir arayüzdür. Sınıf tarafından uygulanması gereken bir yöntemi (getLifecycle()) vardır. Bunun yerine bir uygulama sürecinin tamamını yönetmeye çalışıyorsanız ProcessLifecycleOwner bölümüne bakın.

Bu arayüz, Lifecycle sahipliğini Fragment ve AppCompatActivity gibi ayrı sınıflardan soyutlar ve bunlarla çalışan bileşenler yazmaya olanak tanır. Herhangi bir özel uygulama sınıfı LifecycleOwner arayüzünü uygulayabilir.

DefaultLifecycleObserver kullanan bileşenler, LifecycleOwner kullanan bileşenlerle sorunsuz bir şekilde çalışır. Bunun nedeni, bir gözlemcinin izlemek için kaydolabileceği bir yaşam döngüsü sağlayabilmesidir.

Konum takibi örneğinde, MyLocationListener sınıfının DefaultLifecycleObserver sınıfını uygulatmasını sağlayabilir ve ardından onCreate() yönteminde etkinliğin Lifecycle sınıfıyla başlatabiliriz. Bu, MyLocationListener sınıfının kendi kendine yeterli olmasını sağlar. Yani yaşam döngüsü durumundaki değişikliklere tepki verecek mantık, etkinlik yerine MyLocationListener içinde tanımlanır. Bağımsız bileşenlerin kendi mantıklarını depolaması, etkinliklerin ve parçaların mantığını yönetmeyi kolaylaştırır.

Kotlin

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this, lifecycle) { location ->
            // update UI
        }
        Util.checkUserStatus { result ->
            if (result) {
                myLocationListener.enable()
            }
        }
    }
}

Java

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // update UI
        });
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}

Yaygın bir kullanım alanı, Lifecycle şu anda iyi durumda değilse belirli geri çağırma çağrılarını kullanmaktan kaçınmaktır. Örneğin, geri çağırma etkin durum kaydedildikten sonra bir parça işlemi çalıştırırsa kilitlenme tetiklenir. Bu nedenle, bu geri çağırmayı hiçbir zaman çağırmayı istemeyiz.

Bu kullanım alanını kolaylaştırmak için Lifecycle sınıfı, diğer nesnelerin mevcut durumu sorgulamasına olanak tanır.

Kotlin

internal class MyLocationListener(
        private val context: Context,
        private val lifecycle: Lifecycle,
        private val callback: (Location) -> Unit
): DefaultLifecycleObserver {

    private var enabled = false

    override fun onStart(owner: LifecycleOwner) {
        if (enabled) {
            // connect
        }
    }

    fun enable() {
        enabled = true
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            // connect if not connected
        }
    }

    override fun onStop(owner: LifecycleOwner) {
        // disconnect if connected
    }
}

Java

class MyLocationListener implements DefaultLifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       ...
    }

    @Override
    public void onStart(LifecycleOwner owner) {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @Override
    public void onStop(LifecycleOwner owner) {
        // disconnect if connected
    }
}

Bu uygulamayla LocationListener sınıfımız yaşam döngüsü hakkında her şeyi bilir. LocationListener'mizi başka bir etkinlikten veya parçadan kullanmamız gerekirse yalnızca başlatmamız yeterlidir. Tüm kurulum ve kaldırma işlemleri sınıfın kendisi tarafından yönetilir.

Bir kitaplık, Android yaşam döngüsü ile çalışması gereken sınıflar sağlıyorsa yaşam döngüsü bilincine sahip bileşenler kullanmanızı öneririz. Kitaplık istemcileriniz, istemci tarafında manuel yaşam döngüsü yönetimi olmadan bu bileşenleri kolayca entegre edebilir.

Özel LifecycleOwner uygulama

Destek Kitaplığı 26.1.0 ve sonraki sürümlerdeki Fragment'ler ve Etkinlikler zaten LifecycleOwner arayüzünü uygulamaktadır.

LifecycleOwner yapmak istediğiniz özel bir sınıfınız varsa LifecycleRegistry sınıfını kullanabilirsiniz ancak aşağıdaki kod örneğinde gösterildiği gibi etkinlikleri bu sınıfa yönlendirmeniz gerekir:

Kotlin

class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

Java

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

Yaşam döngüsü bilincine sahip bileşenler için en iyi uygulamalar

  • Kullanıcı arayüzü denetleyicilerinizi (etkinlikler ve parçalar) mümkün olduğunca basit tutun. Kendi verilerini edinmeye çalışmamalı, bunun yerine ViewModel kullanarak verileri edinmeli ve değişiklikleri görünümlere yansıtmak için bir LiveData nesnesini gözlemlemelidir.
  • Kullanıcı arayüzü denetleyicinizin sorumluluğunun, veriler değiştikçe görünümleri güncellemek veya kullanıcı işlemlerini ViewModel'a geri bildirmek olduğu veri odaklı kullanıcı arayüzleri yazmaya çalışın.
  • Veri mantığınızı ViewModel sınıfınıza yerleştirin. ViewModel, kullanıcı arayüzü denetleyiciniz ile uygulamanızın geri kalanı arasında bağlayıcı görevi görmelidir. Ancak veri getirmenin (ör. bir ağdan) ViewModel'un sorumluluğu olmadığını unutmayın. Bunun yerine, ViewModel, verileri almak için uygun bileşeni çağırmalı ve sonucu kullanıcı arayüzü denetleyicisine geri vermelidir.
  • Görünümleriniz ile kullanıcı arayüzü denetleyicisi arasında temiz bir arayüz sağlamak için veri bağlama özelliğini kullanın. Bu sayede görünümlerinizi daha açıklayıcı hale getirebilir ve etkinliklerinizde ve parçalarınızda yazmanız gereken güncelleme kodunu en aza indirebilirsiniz. Bunu Java programlama dilinde yapmayı tercih ediyorsanız standart kodlardan kaçınmak ve daha iyi bir soyutlama elde etmek için Butter Knife gibi bir kitaplık kullanın.
  • Kullanıcı arayüzünüz karmaşıksa kullanıcı arayüzü değişikliklerini yönetmek için bir sunu sınıfı oluşturabilirsiniz. Bu zahmetli bir iş olabilir ancak kullanıcı arayüzü bileşenlerinizin test edilmesini kolaylaştırabilir.
  • ViewModel dosyanızda View veya Activity bağlamına referans vermeyin. ViewModel, etkinliğin ömründen uzun sürerse (yapılandırma değişiklikleri durumunda) etkinliğiniz sızar ve çöp toplayıcı tarafından düzgün şekilde atılmaz.
  • Uzun süren görevleri ve eşzamansız olarak çalışabilecek diğer işlemleri yönetmek için Kotlin coroutine'lerini kullanın.

Yaşam döngüsüne duyarlı bileşenlerin kullanım alanları

Yaşam döngüsü bilincine sahip bileşenler, yaşam döngülerini çeşitli durumlarda yönetmenizi çok daha kolay hale getirebilir. Birkaç örnek:

  • Kaba ve ayrıntılı konum güncellemeleri arasında geçiş yapma. Konum uygulamanız görünür durumdayken ayrıntılı konum güncellemelerini etkinleştirmek ve uygulama arka plandayken kaba güncellemelere geçmek için yaşam döngüsü bilincine sahip bileşenler kullanın. Yaşam döngüsü bilincine sahip bir bileşen olan LiveData, kullanıcınız konum değiştirdiğinde uygulamanızın kullanıcı arayüzünü otomatik olarak güncellemesine olanak tanır.
  • Video arabelleğe alma işlemini durdurma ve başlatma. Videoyu en kısa sürede arabelleğe almak için yaşam döngüsü bilincine sahip bileşenler kullanın ancak oynatmayı, uygulama tamamen başlatılana kadar erteleyin. Uygulamanız yok edildiğinde arabelleğe almayı sonlandırmak için yaşam döngüsü bilincine sahip bileşenleri de kullanabilirsiniz.
  • Ağ bağlantısını başlatma ve durdurma. Bir uygulama ön plandayken ağ verilerinin canlı güncellenmesini (akış) etkinleştirmek ve uygulama arka plana geçtiğinde otomatik olarak duraklatmak için yaşam döngüsü bilincine sahip bileşenler kullanın.
  • Animasyonlu çizilebilir öğeleri duraklatma ve devam ettirme. Uygulama arka plandayken animasyonlu çizilebilir öğeleri duraklatma ve uygulama ön plandayken çizilebilir öğeleri devam ettirme işlemlerini gerçekleştirmek için yaşam döngüsü bilincine sahip bileşenleri kullanın.

Durdurma etkinliklerini işleme

Bir Lifecycle, AppCompatActivity veya Fragment'e ait olduğunda Lifecycle'in durumu CREATED olarak değişir ve AppCompatActivity veya Fragment'nin onSaveInstanceState() işlevi çağrıldığında ON_STOP etkinliği gönderilir.

Bir Fragment veya AppCompatActivity'nin durumu onSaveInstanceState() aracılığıyla kaydedildiğinde, ON_START çağrılana kadar kullanıcı arayüzü değiştirilemez olarak kabul edilir. Durum kaydedildikten sonra kullanıcı arayüzünü değiştirmeye çalışmak, uygulamanızın gezinme durumunda tutarsızlıklara neden olabilir. Bu nedenle, uygulama durum kaydedildikten sonra bir FragmentTransaction çalıştırırsa FragmentManager bir istisna atar. Ayrıntılar için commit() bölümüne bakın.

LiveData, gözlemcinin ilişkili Lifecycle en az STARTED değilse gözlemcisini çağırmaktan kaçınarak bu uç durumu derhal önler. Arka planda, gözlemcisini çağırmaya karar vermeden önce isAtLeast() işlevini çağırır.

Maalesef AppCompatActivity'ın onStop() yöntemi onSaveInstanceState()'den sonra çağrılıyor. Bu durum, kullanıcı arayüzü durumunda değişiklik yapılmasına izin verilmeyen ancak Lifecycle henüz CREATED durumuna taşınmayan bir boşluk bırakır.

Bu sorunu önlemek için beta2 ve sonraki sürümlerdeki Lifecycle sınıfı, etkinliği dağıtmadan durumu CREATED olarak işaretler. Böylece, sistem tarafından onStop() çağrılana kadar etkinlik dağıtılmasa bile mevcut durumu kontrol eden tüm kodlar gerçek değeri alır.

Maalesef bu çözümün iki önemli sorunu vardır:

  • API düzeyi 23 ve önceki sürümlerde Android sistemi, başka bir etkinlik tarafından kısmen kapsansa bile etkinliğin durumunu kaydeder. Diğer bir deyişle, Android sistemi onSaveInstanceState() çağrısı yapar ancak onStop() çağrısı yapmayabilir. Bu durum, kullanıcı arayüzü durumu değiştirilememesine rağmen gözlemcinin yaşam döngüsünün hâlâ etkin olduğunu düşündüğü, potansiyel olarak uzun bir aralık oluşturur.
  • LiveData sınıfına benzer bir davranış sergilemek isteyen tüm sınıfların, Lifecycle beta 2 ve önceki sürümlerde sağlanan geçici çözümü uygulaması gerekir.

Ek kaynaklar

Yaşam döngüsünü yaşam döngüsü bilincine sahip bileşenlerle yönetme hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynakları inceleyin.

Örnekler

Codelab uygulamaları

Bloglar