Süreçlere ve ileti dizilerine genel bakış

Bir uygulama bileşeni başladığında Android sistemi, uygulama için tek bir yürütme iş parçacığı ile yeni bir Linux işlemi başlatır. Varsayılan olarak, aynı uygulamanın tüm bileşenleri main iş parçacığı adı verilen aynı işlem ve iş parçacığında çalışır.

Bir uygulama bileşeni başlarsa ve bu uygulama için zaten bir işlem varsa, uygulamadaki başka bir bileşen zaten başlatılmışsa bileşen bu işlem içinde başlar ve aynı yürütme iş parçacığını kullanır. Ancak uygulamanızdaki farklı bileşenlerin ayrı işlemlerde çalışmasını sağlayabilir ve herhangi bir işlem için ek iş parçacıkları oluşturabilirsiniz.

Bu dokümanda, bir Android uygulamasındaki işlemlerin ve iş parçacıklarının nasıl çalıştığı açıklanmaktadır.

İşlemler

Bir uygulamanın tüm bileşenleri varsayılan olarak aynı işlemde çalışır ve çoğu uygulama bunu değiştirmez. Ancak belirli bir bileşenin hangi sürece ait olduğunu kontrol etmeniz gerekirse bunu manifest dosyasında yapabilirsiniz.

Her bileşen öğesi türünün (<activity>, <service>, <receiver> ve <provider>) manifest girişi, bileşenin çalıştığı işlemi belirtebilen bir android:process özelliğini destekler. Bu özelliği, her bileşenin kendi işleminde çalışacak şekilde veya bazı bileşenler bir işlemi paylaşırken diğerlerinin paylaşmayacağı şekilde ayarlayabilirsiniz.

Uygulamaların aynı Linux kullanıcı kimliğini paylaşması ve aynı sertifikalarla imzalanması koşuluyla, android:process özelliğini farklı uygulamaların bileşenlerinin aynı işlemde çalışacak şekilde de ayarlayabilirsiniz.

<application> öğesi ayrıca, tüm bileşenler için geçerli olan varsayılan bir değer ayarlamak için kullanabileceğiniz android:process özelliğini de destekler.

Kullanıcıya daha çabuk hizmet veren diğer işlemler için kaynaklara ihtiyaç duyulduğunda Android, bir noktada bir işlemi kapatmaya karar verebilir. Kapatılan süreçte çalışan uygulama bileşenleri bu nedenle imha edilir. Yapılacak işler olduğunda bu bileşenler için yeniden bir süreç başlatılır.

Android sistemi, hangi işlemlerin kapatılacağına karar verirken bunların kullanıcı için göreceli önemini dikkate alır. Örneğin, artık ekranda görünmeyen etkinlikleri barındıran bir işlemi, görünür etkinlikleri barındıran bir işleme kıyasla daha kolay kapatır. Bu nedenle, bir sürecin feshedilip sonlandırılmayacağı, o işlemde çalışan bileşenlerin durumuna bağlıdır.

Süreç yaşam döngüsünün ayrıntıları ve bunun uygulama durumlarıyla ilişkisi, Süreçler ve uygulama yaşam döngüsü bölümünde ele alınmıştır.

Mesaj dizileri

Bir uygulama başlatıldığında, sistem uygulama için ana iş parçacığı adı verilen bir yürütme iş parçacığı oluşturur. Bu iş parçacığı, çizim etkinlikleri de dahil olmak üzere etkinlikleri uygun kullanıcı arayüzü widget'larına göndermekten sorumlu olduğu için çok önemlidir. Ayrıca neredeyse her zaman uygulamanızın Android kullanıcı arayüzü araç setindeki android.widget ve android.view paketlerindeki bileşenlerle etkileşimde bulunduğu iş parçacığıdır. Bu nedenle, ana iş parçacığı bazen kullanıcı arayüzü iş parçacığı olarak adlandırılır. Ancak, özel durumlarda bir uygulamanın ana iş parçacığı kullanıcı arayüzü iş parçacığı olmayabilir. Daha fazla bilgi için İleti dizisi ek açıklamaları konusuna bakın.

Sistem, bir bileşenin her örneği için ayrı bir iş parçacığı oluşturmaz. Aynı işlemde çalışan tüm bileşenler kullanıcı arayüzü iş parçacığında örneklenir ve her bileşene yapılan sistem çağrıları bu iş parçacığından gönderilir. Sonuç olarak, sistem geri çağırmalarına yanıt veren yöntemler (ör. kullanıcı işlemlerini raporlamak için onKeyDown() veya yaşam döngüsü geri çağırma yöntemi) her zaman sürecin kullanıcı arayüzü iş parçacığında çalışır.

Örneğin, kullanıcı ekrandaki bir düğmeye dokunduğunda uygulamanızın kullanıcı arayüzü iş parçacığı, dokunma etkinliğini widget'a gönderir. Böylece widget'ın basılma durumunu ayarlar ve etkinlik sırasına geçersiz kılma isteği gönderir. Kullanıcı arayüzü iş parçacığı, isteği sıraya sokar ve widget'a kendisini yeniden çizim yapması için bildirimde bulunur.

Uygulamanızı doğru bir şekilde uygulamazsanız bu tek iş parçacıklı model, uygulamanız kullanıcı etkileşimine yanıt olarak yoğun işler yaptığında düşük performans gösterebilir. Kullanıcı arayüzü iş parçacığında ağ erişimi veya veritabanı sorguları gibi uzun işlemler gerçekleştirmek, kullanıcı arayüzünün tamamını engeller. İleti dizisi engellendiğinde çizim etkinlikleri de dahil hiçbir etkinlik gönderilemez.

Kullanıcı açısından bakıldığında, uygulama askıda duruyor. Daha da kötüsü, kullanıcı arayüzü iş parçacığı birkaç saniyeden uzun süre engellenirse kullanıcıya "Uygulama yanıt vermiyor" (ANR) iletişim kutusu gösterilir. Daha sonra, kullanıcı uygulamanızdan çıkmaya karar verebilir, hatta uygulamanızı kaldırabilir.

Android kullanıcı arayüzü araç setinin ileti dizisi açısından güvenli olmadığını unutmayın. Bu nedenle, kullanıcı arayüzünüzü bir çalışan iş parçacığından değiştirmeyin. Kullanıcı arayüzünüz üzerinde UI iş parçacığından tüm işlemleri yapın. Android'in tek iş parçacığı modelinin iki kuralı vardır:

  1. Kullanıcı arayüzü iş parçacığını engellemeyin.
  2. Android kullanıcı arayüzü araç setine, kullanıcı arayüzü iş parçacığının dışından erişmeyin.

Çalışan ileti dizileri

Bu tek iş parçacığı modeli nedeniyle uygulamanızın kullanıcı arayüzünün yanıt verme hızı açısından, UI iş parçacığını engellememeniz çok önemlidir. Anında olmayan işlemleriniz varsa bunları ayrı arka plan veya çalışan iş parçacıklarında yaptığınızdan emin olun. Kullanıcı arayüzünü, kullanıcı arayüzü veya "ana iş parçacığı" dışında bir iş parçacığından güncelleyemeyeceğinizi unutmayın.

Android, bu kurallara uymanıza yardımcı olmak amacıyla diğer iş parçacıklarından kullanıcı arayüzü iş parçacığına erişmek için çeşitli yöntemler sunar. Size yardımcı olabilecek yöntemlerin bir listesi aşağıda verilmiştir:

Aşağıdaki örnekte View.post(Runnable) kullanılmıştır:

Kotlin

fun onClick(v: View) {
    Thread(Runnable {
        // A potentially time consuming task.
        val bitmap = processBitMap("image.png")
        imageView.post {
            imageView.setImageBitmap(bitmap)
        }
    }).start()
}

Java

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // A potentially time consuming task.
            final Bitmap bitmap =
                    processBitMap("image.png");
            imageView.post(new Runnable() {
                public void run() {
                    imageView.setImageBitmap(bitmap);
                }
            });
        }
    }).start();
}

Arka plan işlemi ayrı bir iş parçacığından yapılırken ImageView her zaman kullanıcı arayüzü iş parçacığından düzenlendiği için bu uygulama iş parçacığında güvenlidir.

Ancak işlemin karmaşıklığı arttıkça bu tür kodlar karmaşık ve bakımı zor olabilir. Bir çalışan iş parçacığıyla daha karmaşık etkileşimleri yönetmek amacıyla, kullanıcı arayüzü iş parçacığından gönderilen mesajları işlemek için çalışan iş parçacığınızda Handler kullanmayı düşünebilirsiniz. Arka plan iş parçacıkları üzerinde çalışmayı planlama ve kullanıcı arayüzü iş parçacığıyla tekrar iletişim kurma hakkında tam bir açıklama için Arka Plan Çalışmasına Genel Bakış bölümüne bakın.

İş parçacığı güvenli yöntemler

Bazı durumlarda, uyguladığınız yöntemler birden fazla iş parçacığından çağrılır ve bu nedenle iş parçacığı güvenli olacak şekilde yazılması gerekir.

Bu öncelikle bağlı bir hizmetteki yöntemler gibi uzaktan çağrılabilen yöntemler için geçerlidir. IBinder içinde uygulanan bir yönteme yapılan çağrı, IBinder uygulamasının çalıştığı işlemden kaynaklandığında yöntem çağrıyı yapan iş parçacığında yürütülür. Ancak çağrı başka bir işlemden kaynaklandığında, yöntem sistemin IBinder ile aynı işlemde tuttuğu iş parçacıklarından oluşan bir havuzdan seçilen bir iş parçacığında yürütülür. İşlemin kullanıcı arayüzü iş parçacığında yürütülmez.

Örneğin, bir hizmetin onBind() yöntemi hizmet sürecinin kullanıcı arayüzü iş parçacığından çağrılırken onBind() nesnesinin döndürdüğü nesnede uygulanan yöntemler (uzak prosedür çağrısı (RPC) yöntemlerini uygulayan bir alt sınıf gibi) havuzdaki iş parçacıklarından çağrılır. Bir hizmet birden fazla istemciye sahip olabileceğinden, aynı IBinder yöntemini kullanan birden fazla havuz iş parçacığı aynı anda etkileşimde bulunabilir. Bu nedenle, IBinder yöntemlerinin iş parçacığı güvenli olacak şekilde uygulanması gerekir.

Benzer şekilde, içerik sağlayıcı başka işlemlerden kaynaklanan veri isteklerini alabilir. ContentResolver ve ContentProvider sınıfları, işlemler arası iletişimin (IPC) nasıl yönetildiğinin ayrıntılarını gizler. Ancak bu isteklere yanıt veren ContentProvider yöntemleri (query(), insert(), delete(), update() ve getType() yöntemleri), sürecin kullanıcı arayüzü iş parçacığından değil, içerik sağlayıcının sürecindeki iş parçacıkları havuzundan çağrılır. Bu yöntemler, aynı anda herhangi bir sayıda iş parçacığından çağrılabileceğinden, iş parçacığı güvenli olacak şekilde uygulanmaları gerekir.

İşlemler arası iletişim

Android, RPC'leri kullanan IPC için bir mekanizma sunar. Bu mekanizmada yöntem, bir etkinlik veya başka bir uygulama bileşeni tarafından çağrılıp başka bir işlemde uzaktan yürütülür ve herhangi bir sonuç arayan kişiye geri döndürülür. Bu, bir yöntem çağrısının ve içerdiği verilerin işletim sisteminin anlayabileceği bir düzeye ayrıştırılmasını, yerel işlem ve adres alanından uzak işleme ve adres alanına aktarılmasını ve ardından çağrıyı burada yeniden derleyip yeniden düzenlemeyi içerir.

Daha sonra döndürülen değerler ters yönde aktarılır. Android, bu IPC işlemlerini gerçekleştirmek için gereken tüm kodları sağlar. Böylece RPC programlama arayüzünü tanımlamaya ve uygulamaya odaklanabilirsiniz.

IPC'yi gerçekleştirmek için uygulamanız bindService() kullanarak bir hizmete bağlanmalıdır. Daha fazla bilgi için Hizmetlere genel bakış başlıklı makaleyi inceleyin.