Gönderi yöntemi tam olarak ne yapar?


106

Çok garip bir özellikle karşılaştım.

Ana iş parçacığı üzerinde bir animasyon çalıştırmaya çalıştığımda başlamıyor. Söz konusu animasyonu kullanarak çalıştırdığımda

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

Başlıyor.

CurrentThreadAnimasyona başlamadan önce yazdırdım ve her ikisi de yazdırdım main.

Açıkçası, burada bir şeyi kaçırıyorum, çünkü her ikisi de ana iş parçacığındaki animasyonu başlatmalı ... Benim tahminim post görevi sıraya ekledikçe, daha "doğru bir zamanda" başlıyor, ancak bilmek isterim burada daha derinlerde neler oluyor.

DÜZENLEME: İşleri açıklığa kavuşturmama izin verin - sorum şu ki, ana iş parçacığı üzerinde animasyonu başlatırken neden postadaki animasyonu başlatmanın başlamasına neden oluyor?


Bu davranış bir Android sürümüne özel mi? Android 4.1.2'de yeniden oluşturamadım!
Akdeniz

Bu davranışı Android 2.3.3'te yeniden oluşturdum. Ama için AnimationDrawable! Sıradan Animationörnek, her kurulumda başarılı bir şekilde canlandırılmaya başladı. Gelen AnimationDrawabledurumunda; onu başlatmaya çalıştığınızda onCreate, o anda görüntülemeye bağlı olmadığınız için başlamıyor. Yani bu bir iş parçacığı sorunu değil AnimationDrawable. Belki aynı şey için de geçerlidir Animation? developer.android.com/guide/topics/graphics/…
Akdeniz

Yanıtlar:


161

post : post, Runnable'ın mesaj kuyruğuna eklenmesine neden olur,

Runnable: Yürütülebilen bir komutu temsil eder. Genellikle kodu farklı bir Thread'de çalıştırmak için kullanılır.

run () : Sınıfın kodunun aktif bölümünü çalıştırmaya başlar. Bu yöntem, Runnable'ı uygulayan bir sınıfla oluşturulan bir iş parçacığı başlatıldığında çağrılır.

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

kod :getView().startAnimation(a);

kodunuzda,

post, Runnable'ın ( kod farklı bir iş parçacığında çalıştırılacak) mesaj kuyruğunu eklemesine neden olur .

Yani startAnimation, messageQueue'dan alındığında yeni bir iş parçacığında tetiklenecek

[DÜZENLE 1]

Neden UI iş parçacığı (ana iş parçacığı) yerine yeni bir iş parçacığı kullanıyoruz?

UI İş Parçacığı:

  • Uygulama başladığında, Ui Thread otomatik olarak oluşturulur

  • olayları uygun aletlere göndermekten sorumludur ve bu çizim olaylarını içerir.

  • Aynı zamanda Android widget'larıyla etkileşim kurduğunuz konu

Örneğin, ekrandaki bir düğmeye dokunursanız, UI iş parçacığı dokunmatik olayını parçacığa gönderir ve bu da daha sonra basılmış durumunu ayarlar ve olay kuyruğuna bir geçersiz kılma isteği gönderir. UI iş parçacığı, isteği çıkarır ve parçacığın kendisini yeniden çizmesi için bilgilendirir.

Bir kullanıcı longOperation yapacak bir düğmeye basarsa ne olur?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});

Kullanıcı arayüzü donuyor. Hatta program çökebilir.

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}

Kullanıcı arayüzünü hiçbir zaman doğrudan çalışan iş parçacığından güncellemeyen android kuralını bozar

Android, UI iş parçacığına diğer iş parçacıklarından erişmenin birkaç yolunu sunar.

  • Activity.runOnUiThread (Çalıştırılabilir)
  • View.post (Çalıştırılabilir)
  • View.postDelayed (Runnable, long)
  • İşleyici

Aşağıdaki gibi

View.post (Çalıştırılabilir)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

İşleyici

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}

görüntü açıklamasını buraya girin

Daha fazla bilgi için

http://android-developers.blogspot.com/2009/05/peless-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/


15
Öyleyse, her ikisi de sonunda aynı iş parçacığı üzerinde çalışırken, animasyonu gönderide başlatmak, ana iş parçacığında çalıştırmaktan neden farklı?
Gal

Çünkü bu tek iş parçacığı modeli Android uygulamalarında düşük performans sağlayabilir.
Talha

1
Düşük performansın bir animasyon göstermemekle ne alakası var?
Gal

17
Bunun soruyu yanıtladığını sanmıyorum, bu daha çok ui-thread ve multi threading hakkında hiçbir şey bilmeyen yeni başlayanlar için genel bir cevap gibi. Bu, animasyonu sıraya atmanın neden animasyonu çalıştırdığını açıklamıyor; bir animasyonun herhangi bir post () veya runOnUiThread () hilesi kullanmadan doğrudan ui-thread içinde çalıştırılacağı varsayılır.
carrizo

3
Tüm UI çalışmaları Ana iş parçacığında (UI iş parçacığı) olmalıdır. Ana iş parçacığında hemen çağrı yerine post () kullanarak animasyonun çalışmasını sağlayan püf noktası Zaman: Ana ileti dizisinde hemen ararsanız, bu "animasyonu şimdi başlat" dediğiniz anlamına gelir, Ancak şu anda görüntü hazır olmayabilir animasyon için (ölçü, çiz ...). Ancak bunu post () 'a koyarsanız, animasyonu hazır hale getirmek için bazen startAnimation'ı kuyruğa alır.
NguyenDat

35

Bu onCreate veya onCreateView'de mi yapılıyor? Öyleyse, uygulama, Görünümün pencereye eklendiği bir durumda olmayabilir. Görünüm ölçümleri ve konumu gibi şeyler hesaplanmamış olabileceğinden, Görünüm ölçümlerine dayalı birçok algoritma çalışmayabilir. Android animasyonları genellikle bunların UI matematiğinden geçmesini gerektirir

View.post aslında animasyonu Görünüm'ün mesaj döngüsünde sıraya koyar, bu nedenle görünüm pencereye eklendiğinde, animasyonu manuel olarak yürütmek yerine yürütür.

Aslında UI iş parçacığında bir şeyler çalıştırıyorsunuz, ancak farklı bir zamanda


Kabul edilen yanıt, posterin "postanın Runnable'a neden olduğunu (kod farklı bir iş parçacığında çalıştırılacaktır)" ifadesini içeren yanıltıcıdır. Bu doğru cevap "Aslında UI iş parçacığında, ancak farklı bir zamanda bir şeyler çalıştırıyorsunuz" - artı 1
smitty1

18

İyi bir cevap için buraya bir göz atın . view.post () handler.post () ile hemen hemen aynıdır. Ana iş parçacığı kuyruğuna girer ve diğer bekleyen görevler tamamlandıktan sonra yürütülür. Activity.runOnUiThread () öğesini çağırırsanız, kullanıcı arabirimi iş parçacığında hemen çağrılacaktır.


31
Bulduğum büyük (ve son derece yararlı) bir fark, view.post () içindeki çalıştırılabilir öğenin, View ilk gösterildiğinde çağrılacak olmasıdır. IE, bunu Görünümün şişirilmesi üzerine bir animasyon başlatacak şekilde ayarlayabilir ve daha sonra gelecekte bir noktada, son olarak görünüm hiyerarşisine ekleyebilirsiniz. Bu noktada, animasyon çalışacak ve bunun için endişelenmenize gerek kalmayacak.
Deev

Aslında, handler.post () ana iş parçacığı üzerinde her zaman bir ileti / çalıştırılabilirlik göndermez. İşleyicinin nasıl oluşturulduğuna bağlıdır (farklı bir iş parçacığı üzerindeki bir Looper ile ilişkilendirilebilir). Öte yandan, view.post () her zaman ana ileti dizisinde çalışacaktır
Yair Kukielka

4

Sanırım sorun, post () yöntemini çağırdığınız yaşam döngüsü yöntemi olabilir. Bunu onCreate () içinde mi yapıyorsunuz? öyleyse, etkinliğin onResume () belgelerinde ne bulduğuma bakın:

Özgeçmişte()

API düzeyinde void onResume (), etkinliğinizin kullanıcıyla etkileşime girmeye başlaması için onRestoreInstanceState (Bundle), onRestart () veya onPause () sonrasında çağrılır. Burası animasyonlara başlamak , özel erişimli cihazları (kamera gibi) açmak vb. İçin iyi bir yerdir .

https://developer.android.com/reference/android/app/Activity.html#onResume ()

Bu nedenle, Joe Plante'nin dediği gibi, post () öğesini çağırdığınız anda görünüm animasyonları başlatmaya hazır olmayabilir, bu nedenle onu onResume () öğesine taşımayı deneyin.

PD: Aslında kodu onResume () öğesine taşırsanız, o zaman zaten ui-thread içinde olduğunuzdan ve görünümün animasyonları başlatmaya hazır olması gerektiğinden post () çağrısını kaldırabileceğinizi düşünüyorum.


3
onResumebaşlangıçta "görünüm hazır olduğunda" birden çok kez çağrılabilir (ekranlar uykuya geçer, aktivite arka diziye itilir, vb.). Den çağrılırsa, onResumebirden çok kez (yeniden) başlamayı önlemek için animasyonun başlamış olduğu hava durumunu izlemek için bir bayrak gerekebilir.
samis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.