Yaşam Döngüsüne Duyarlı Bileşenlerle Yaşam Döngülerini Yönetme Android Jetpack'in bir parçasıdır.

Yaşam döngüsüne duyarlı bileşenler, başka bir bileşenin yaşam döngüsü durumundaki değişikliğe (ör. etkinlikler ve parçalar) yanıt olarak eylemler gerçekleştirir. Bu bileşenler, bakımı daha kolay olan daha düzenli ve genellikle daha hafif kodlar üretmenize yardımcı olur.

Bağımlı bileşenlerin eylemlerini, aktivite ve parçalara ait yaşam döngüsü yöntemlerinde uygulamak da yaygın görülen 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şenler kullanarak bağımlı bileşenlerin kodunu yaşam döngüsü yöntemlerinden çıkarıp bileşenlerin içine taşıyabilirsiniz.

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

Android Framework'te tanımlanan uygulama bileşenlerinin çoğuna yaşam döngüleri vardır. Yaşam döngüleri, işletim sistemi veya sürecinizde çalışan çerçeve kodu tarafından yönetilir. Bunlar, Android'in çalışma şeklinin temelini oluşturur ve uygulamanız bunlara uymalıdır. Bunu yapmamak bellek sızıntılarını, hatta uygulama kilitlenmelerini tetikleyebilir.

Ekranda cihazın konumunu gösteren bir etkinliğimiz olduğunu düşünün. Yaygın 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 girilmesini gerektirir. Bu durum, bileşenlerin bakımlarını zorlaştırır.

Ayrıca, bileşenin etkinlik veya parça durdurulmadan önce başlayacağının garantisi yoktur. Bu durum özellikle, onStart()'teki yapılandırma kontrolleri gibi uzun süreli bir işlem gerçekleştirmemiz gerektiğinde geçerlidir. Bu, onStop() yönteminin onStart()'dan önce bittiği ve bileşenin gerekenden daha uzun süre dayandığı 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 ayrı bir yöntemle çözmenize yardımcı olacak sınıflar ve arayüzler sağlar.

Yaşam döngüsü

Lifecycle, bir bileşenin (etkinlik veya parça gibi) 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 numara 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ı gösteren diyagram
Şekil 1. Android etkinlik yaşam döngüsünü oluşturan durumlar ve etkinlikler

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

Bir sınıf, DefaultLifecycleObserver etiketini uygulayıp 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ğırarak ve 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.

Yaşam DöngüsüSahibi

LifecycleOwner, sınıfta bir Lifecycle olduğunu belirten tek yöntem arayüzüdür. Sınıf tarafından uygulanması gereken getLifecycle() adlı bir yönteme sahiptir. Bunun yerine, tüm uygulama sürecinin yaşam döngüsünü yönetmeye çalışıyorsanız ProcessLifecycleOwner sayfasını inceleyin.

Bu arayüz, Lifecycle sahipliğini Fragment ve AppCompatActivity gibi ayrı ayrı sınıflardan soyutlar ve bu öğelerle çalışan bileşenlerin yazılmasına olanak tanır. LifecycleOwner arayüzünü herhangi bir özel uygulama sınıfı uygulayabilir.

DefaultLifecycleObserver uygulayan bileşenler, LifecycleOwner uygulayan bileşenlerle sorunsuz bir şekilde çalışır. Çünkü sahip, bir gözlemcinin izlemek için kaydedebileceği bir yaşam döngüsü sağlayabilir.

Konum izleme örneğinde, MyLocationListener sınıfının DefaultLifecycleObserver uygulamasını uygulayıp ardından onCreate() yönteminde etkinliğin Lifecycle ile başlamasını sağlayabiliriz. Bu, MyLocationListener sınıfının kendi kendine yeterli olmasını sağlar. Diğer bir deyişle, yaşam döngüsü durumundaki değişikliklere tepki verme mantığı, etkinlik yerine MyLocationListener öğesinde tanımlanır. Bağımsız bileşenlerin kendi mantığını depolaması, etkinlikler ve parçalar mantığının yönetimini 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ı, Lifecyclenın şu anda iyi durumda olmaması durumunda belirli geri çağırmaların çağrılmamasıdır. Örneğin, geri çağırma, etkinlik durumu kaydedildikten sonra bir parça işlemi çalıştırırsa bir kilitlenmeyi tetikler. Bu nedenle, hiçbir zaman bu geri çağırmayı çağırmak 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 uygulama sayesinde LocationListener sınıfımız, yaşam döngüsüne tamamen duyarlı olur. LocationListener öğemizi başka bir etkinlikten veya parçadan kullanmamız gerekirse başlatmamız gerekir. Tüm kurulum ve söküm işlemleri, sınıfın kendisi tarafından yönetilir.

Bir kitaplık, Android yaşam döngüsüyle çalışması gereken sınıflar sağlıyorsa yaşam döngüsüne duyarlı bileşenler kullanmanızı öneririz. Kitaplık istemcileriniz, istemci tarafında manuel yaşam döngüsü yönetimine gerek kalmadan bu bileşenleri kolayca entegre edebilir.

Özel bir Yaşam Döngüsü Sahibi uygulama

Destek Kitaplığı 26.1.0 ve sonraki sürümlerindeki Parçalar ve Etkinlikler LifecycleOwner arayüzünü zaten uygulamaktadır.

LifecycleOwner oluşturmak 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üne duyarlı bileşenler için en iyi uygulamalar

  • Kullanıcı arayüzü denetleyicilerinizi (etkinlikler ve parçalar) mümkün olduğunca sade tutun. Kendi verilerini elde etmeye çalışmamalıdır. Bunun yerine, bunu yapmak için bir ViewModel kullanmalı ve değişiklikleri görünümlere geri yansıtmak için bir LiveData nesnesi gözlemlemelidir.
  • Kullanıcı arayüzü denetleyicinizin sorumluluğunun, veri değiştikçe görünümleri güncellemek veya kullanıcı işlemlerini tekrar ViewModel'a bildirmek olduğu veriye dayalı kullanıcı arayüzleri yazmayı deneyin.
  • 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örür. Ancak dikkatli olun, (örneğin bir ağdan) veri getirme sorumluluğu ViewModel'un sorumluluğu değildir. Bunun yerine ViewModel, verileri getirmek için uygun bileşeni çağırmalı ve ardından sonucu kullanıcı arayüzü denetleyicisine sunmalıdır.
  • Görünümleriniz ve kullanıcı arayüzü denetleyicisi arasında temiz bir arayüz sağlamak için Veri Bağlama özelliğini kullanın. Böylece, görünümlerinizi daha açıklayıcı hale getirebilir ve etkinliklerinize ve parçalarınıza yazmak için ihtiyacınız olan güncelleme kodunu en aza indirebilirsiniz. Bunu Java programlama dilinde yapmayı tercih ederseniz ortak koddan 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 işlemek için bir sunucu sınıfı oluşturabilirsiniz. Bu zahmetli bir iş olabilir, ancak kullanıcı arayüzü bileşenlerinizin test edilmesini kolaylaştırabilir.
  • ViewModel etiketinizde bir View veya Activity bağlamına referans vermekten kaçının. ViewModel etkinliği geçerliliğini yitirirse (yapılandırma değişikliği durumunda) etkinliğiniz sızdırılır ve çöp toplayıcı tarafından uygun şekilde imha edilmez.
  • Uzun süreli görevleri ve eşzamansız olarak çalışabilen diğer işlemleri yönetmek için Kotlin eş yordamlarını kullanın.

Yaşam döngüsüne duyarlı bileşenler için kullanım alanları

Yaşam döngüsüne duyarlı bileşenler, çeşitli durumlarda yaşam döngülerini yönetmenizi çok kolaylaştırabilir. Aşağıda birkaç örnek verilmiştir:

  • Yaklaşık 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 için yaşam döngüsüne duyarlı bileşenler kullanın ve uygulama arka plandayken genel ayrıntılı güncellemelere geçin. Yaşam döngüsüne duyarlı 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üncellemesini sağlar.
  • Videonun arabelleğe alınması durdurulup başlatılıyor. Videoyu arabelleğe almaya en kısa sürede başlamak için yaşam döngüsüne duyarlı bileşenler kullanın ancak oynatma işlemini uygulama tam olarak başlatılana kadar erteleyin. Uygulamanız kaldırıldığında arabelleğe almayı sonlandırmak için yaşam döngüsüne duyarlı bileşenler de kullanabilirsiniz.
  • Ağ bağlantısını başlatma ve durdurma. Uygulama ön plandayken ağ verilerinin canlı güncellenmesini (akışını) etkinleştirmek ve uygulama arka plana geçtiğinde otomatik olarak duraklatmak için yaşam döngüsüne duyarlı bileşenler kullanın.
  • Animasyonlu çizimleri duraklatma ve devam ettirme. Uygulama arka plandayken animasyonlu çekilebilir öğeleri duraklatmak ve uygulama ön plandayken çekilebilir öğeleri devam ettirmek için yaşam döngüsüne duyarlı bileşenler kullanın.

Durma etkinliklerini işleme

Bir Lifecycle bir AppCompatActivity veya Fragment alanına aitse Lifecycle durumu, AppCompatActivity veya Fragment öğesinin onSaveInstanceState() öğesi çağrıldığında CREATED olarak değişir ve ON_STOP etkinliği gönderilir.

Bir Fragment veya AppCompatActivity durumu onSaveInstanceState() aracılığıyla kaydedildiğinde ON_START çağrılana kadar kullanıcı arayüzü sabit kabul edilir. Durum kaydedildikten sonra kullanıcı arayüzünde değişiklik yapmaya çalışmak, uygulamanızın gezinme durumunda tutarsızlıklara yol açabilir. Bu nedenle, uygulama kaydedildikten sonra FragmentTransaction çalıştırırsa FragmentManager istisna oluşturur. Ayrıntılar için commit() sayfasını inceleyin.

LiveData, gözlemcinin ilişkili Lifecycle öğesi en azından STARTED değilse gözlemciyi çağırmak yerine bu sıra dışı durumu hemen engeller. Perde arkasında, gözlemcisini çağırmaya karar vermeden önce isAtLeast() çağrısı yapar.

Maalesef AppCompatActivity'in onStop() yönteminin adı sonra onSaveInstanceState(). Bu da kullanıcı arayüzü durum değişikliklerine izin verilmeyen ancak Lifecycle henüz CREATED durumuna taşınmayan bir boşluk bırakıyor.

Bu sorunu önlemek için beta2 sürümündeki Lifecycle sınıfı ve daha düşük bir değer, etkinliği göndermeden durumu CREATED olarak işaretler. Böylece, geçerli durumu kontrol eden tüm kodlar gerçek değeri alır. Böylece etkinlik, onStop() sistem tarafından çağrılana kadar dağıtılmaz.

Ne yazık ki bu çözümde iki önemli sorun var:

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

Ek kaynaklar

Yaşam döngüsüne duyarlı bileşenlerle yaşam döngülerini yönetme hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara başvurun.

Sana Özel

Codelab uygulamaları

Bloglar