Android Bilgi Notları: 2 "yanlış anlaşılan" Android bilgi puanını kaydedin

Bugün, daha önce yanılmış olabileceğimiz iki Android bilgi noktasını paylaşacağım. Hâlâ nihai noktaya ulaşmak ve anlamadığımız sorunları anlamak zorundayız ~

1. Etkinlik önce DecorView'e mi yoksa Pencere'ye mi ulaşıyor?

Bir sabah olay dağıtımıyla ilgili bir tartışma gördüm:

Dolayısıyla, etkinliğin önce DecorView'e mi yoksa Pencereye (Etkinlik, İletişim Kutusu) mı geldiği, iki soruyu gündeme getirir:

1. Dokunmayla ilgili olayların DecorView, PhoneWindow ve Activity / Dialog arasında aktarılma sırası nedir?

2. Neden 1'e göre tasarlanmıştır?

Cevap: Etkinlik önce DecorView'e gelir

Giriş sistemi

Kullanıcı ekrana dokunduğunda veya tuşlara bastığında, donanım sürücüsü ilk kez tetiklenir.Sürücü olayı aldıktan sonra, karşılık gelen olayı en ilkel çekirdek olayını oluşturan giriş aygıtı düğümüne yazar.

Ardından, giriş sistemi, katmanlı kapsüllemeden sonra KeyEvent veya MotionEvent haline gelen orijinal ekolojik olayı çıkarır;

Son olarak, giriş olayını tüketmek için ilgili hedef pencereye (Pencere) gönderilir.

1. Ekrana dokunulduğunda, Linux çekirdeği, donanım tarafından oluşturulan dokunma olayını Olay olarak paketleyecek ve / dev / input / event dizininde depolayacaktır.

2. Giriş sistemi - InputReader iş parçacığı: Döngü yapın ve / dev / input / klasöründen girdi olaylarını sürekli olarak okumak için EventHub'ın getEvent () öğesini çağırmasına izin verin. Daha sonra EventEntry'ye dönüştürülür ve InputDispatcher'ın mInboundQueue'sine eklenir.

3. Giriş sistemi - InputDispatcher iş parçacığı: mInboundQueue kuyruğundaki olayları çıkarın, bunları DispatchEntry olaylarına dönüştürün ve bunları bağlantının outboundQueue kuyruğuna ekleyin. Ardından, dağıtım olayını işlemeye başlayın (örneğin, bunu ViewRootImpl'nin WindowInputEventReceiver'ına dağıtın), giden kuyruğunu çıkarın ve waitQueue'ya koyun.

4. Giriş sistemi-UI iş parçacığı: "InputDispatcher" iş parçacığında ve odaklanmış pencerenin bulunduğu sürecin UI ana iş parçacığında bulunan, birbirleriyle iletişim kurabilen soket çiftleri oluşturun.

Bunun hakkında sadece burada konuşuyorum. Ayrıntılar için lütfen bu makaleye bakın: Gityuan'ın Tüm İşlemi Giriş Sistemi-Olay İşleme Makalenin 3.3.3 Bölümü, Yerel katmandan dağıtılan Çerçeve katmanının InputEventReceiver.dispachInputEvent () ile ilgili konuşuyor.

Çerçeve katmanı

//InputEventReceiver.dispachInputEvent () private void dispatchInputEvent (int seq, InputEvent olayı) { mSeqMap.put (event.getSequenceNumber (), seq); onInputEvent (olay); }

ViewRootImpl.WindowInputEventReceiver

Yerel katman, Çerçeve katmanının InputEventReceiver.dispachInputEvent () öğesini JNI aracılığıyla yürütür ve gerçekte adı, InputEventReceiver'ı devralan ViewRootImpl.WindowInputEventReceiver'dır.

Dolayısıyla, WindowInputEventReceiver öğesinin dispachInputEvent () işlevi burada yürütülür:

son sınıf WindowInputEventReceiver, InputEventReceiver'ı genişletir { public void onInputEvent (InputEvent olayı) { enqueueInputEvent (olay, bu, 0, doğru); } ... }

ViewRootImpl

void enqueueInputEvent (InputEvent olayı, InputEventReceiver alıcısı, int bayrakları, boole süreciHemen) { ... if (hemen işleyin) { // Anahtar nokta: Girdi olayını yürütür doProcessInputEvents (); } Başka { // İşleyicinin gecikmeli işleme olayını gözden geçirin programProcessInputEvents (); } } void doProcessInputEvents () { while (mPendingInputEventHead! = null) { QueuedInputEvent q = mPendingInputEventHead; mPendingInputEventHead = q.mNext; if (mPendingInputEventHead == null) { mPendingInputEventTail = null; } q.mNext = boş; mPendingInputEventCount - = 1; Trace.traceCounter (Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName, mPendingInputEventCount); long eventTime = q.mEvent.getEventTimeNano (); long oldestEventTime = eventTime; if (q.mEvent instanceof MotionEvent) { MotionEvent me = (MotionEvent) q.mEvent; eğer (me.getHistorySize () > 0) { oldestEventTime = me.getHistoricalEventTimeNano (0); } } mChoreographer.mFrameInfo.updateInputEventTime (eventTime, oldestEventTime); // Anahtar nokta: daha fazla gönderme olayı işleme deliveryInputEvent (q); } ... } private void deliveryInputEvent (QueuedInputEvent q) { Trace.asyncTraceBegin (Trace.TRACE_TAG_VIEW, "deliveryInputEvent", q.mEvent.getSequenceNumber ()); if (mInputEventConsistencyVerifier! = null) { mInputEventConsistencyVerifier.onInputEvent (q.mEvent, 0); } Giriş Aşaması aşaması; if (q.shouldSendToSynthesizer ()) { stage = mSyntheticInputStage; } Başka { stage = q.shouldSkipIme ()? mFirstPostImeInputStage: mFirstInputStage; } if (stage! = null) { // Önemli nokta: Yukarıdakiler, olayı işlenmek üzere bu InputStage'e göndermeye karar verdi stage.deliver (q); } Başka { finishInputEvent (q); }

ViewRootImpl.ViewPostImeInputStage

Önceki olay, işleme için ViewRootImpl.ViewPostImeInputStage'e gönderilir ve ana InputStage.deliver () yöntemi, Touch olayını işlemek için apply () öğesini çağırır:

@Override korumalı int onProcess (QueuedInputEvent q) { if (q.mEvent instanceof KeyEvent) { return processKeyEvent (q); } Başka { final int kaynak = q.mEvent.getSource (); eğer ((kaynak ve InputDevice.SOURCE_CLASS_POINTER)! = 0) { // Önemli nokta: dağıtım dokunma olayını yürütün return processPointerEvent (q); } else if ((kaynak ve InputDevice.SOURCE_CLASS_TRACKBALL)! = 0) { return processTrackballEvent (q); } Başka { dönüş processGenericMotionEvent (q); } } } private int processPointerEvent (QueuedInputEvent q) { final MotionEvent olayı = (MotionEvent) q.mEvent; ... // Anahtar nokta: mView, Touch olaylarını dağıtır, mView ise DecorView'dur işlenen boole = mView.dispatchPointerEvent (olay); belkiUpdatePointerIcon (olay); belkiUpdateTooltip (olay); ... }

DecorView

Android'in Penceresine aşina iseniz, Activity ve Dialog'a karşılık gelen ViewRootImpl üyesi mView, DecorView'dur ve Görünüm'ün dispatchPointerEvent () kodu aşağıdaki gibidir:

//View.java public final boolean dispatchPointerEvent (MotionEvent olayı) { if (event.isTouchEvent ()) { // Dokunma olayını dağıtın return dispatchTouchEvent (olay); } Başka { return dispatchGenericMotionEvent (olay); } }

DecorView FrameLayout'u miras aldığından, DecorView'in dispatchTouchEvent () öğesi yukarıda çağrılacaktır:

@Override public boolean dispatchTouchEvent (MotionEvent ev) { final Window.Callback cb = mWindow.getCallback (); return cb! = null! mWindow.isDestroyed () mFeatureId < 0 ? cb.dispatchTouchEvent (ev): super.dispatchTouchEvent (ev); }

Yukarıdaki Window.Callback, Activity ve Dialog tarafından gerçekleştirilir, bu nedenle cb değişkeni Activity ve Dialog olabilir.

Aktivite

Yukarıdaki cb Activity olduğunda, Activity'nin dispatchTouchEvent () işlevini yürütün:

public boolean dispatchTouchEvent (MotionEvent ev) { eğer (ev.getAction () == MotionEvent.ACTION_DOWN) { onUserInteraction (); } if (getWindow (). superDispatchTouchEvent (ev)) {// Anahtar nokta: getWindow (). superDispatchTouchEvent (ev) doğruya dön; } return onTouchEvent (ev); }

Android'in Penceresine aşina iseniz, Activity'nin getWindow () öğesi PhoneWindow'u alacaktır. Aşağıda PhoneWindow kodu verilmiştir:

//PhoneWindow.java @Override public boolean superDispatchTouchEvent (MotionEvent olayı) { // DecorView'ün superDispatchTouchEvent'i çağırın mDecor.superDispatchTouchEvent (olay) döndür; }

İşte DecorView.superDispatchTouchEvent () kodu:

//DecorView.java public boolean superDispatchTouchEvent (MotionEvent olayı) { // Ortak Touch olayları dağıtımımızı başlatmak için ViewGroup'un dispatchTouchEvent () öğesini çağırın return super.dispatchTouchEvent (olay); }

akış şeması

Cevap: Neden DecorView- > Aktivite- > PhoneWindow- > DecorView etkinlikleri geçer mi?

Ayrışma!

ViewRootImpl, Activity diye bir şey olduğunu bilmiyor! Sadece DecorView'i tutar.

Bu nedenle, dokunma olaylarını Activity.dispatchTouchEvent () öğesine doğrudan gönderemezsiniz;

Öyleyse, dokunma olayı Activity.dispatchTouchEvent () 'e geldiğine göre, neden onu doğrudan DecorView'a dağıtıp PhoneWindow aracılığıyla dolaylı olarak göndermiyorsunuz?

Çünkü Activity, DecorView olduğunu bilmiyor! Bununla birlikte, Activity PhoneWindow'u tutar ve PhoneWindow tabii ki penceresinde ne olduğunu bilir, böylece olayları DecorView'a gönderebilir.

Android'de Activity, Penceresinde ne olduğunu bilmez, bu nedenle bağlantı çok düşüktür.

Başka bir Pencere deneyelim mi?

Pencerenin içeriğinden bağımsız olarak, Pencere Faaliyet tarafından belirlenen standartlara uymaya devam ettiği sürece, Faaliyette iyi çalışabilir. Elbette bu, ayrıştırmanın ölçeklenebilirlik avantajıdır.

Yukarıdaki cevap için teşekkürler: Cai Xukun basketbol oynuyor.

2. RecyclerView kartında tutulan kaynaklar ne zaman serbest bırakılmalıdır?

View'ın onAttachedToWindow ve onDetachedFromWindow çağrı zamanlamasını tartışmadan önce.

Bu mekanizma RecyclerView kartlarında hala geçerli mi?

Örneğin, RecyclerView Öğesinin onBindViewHolder öğesinde bir geri sayım ekranı yapmak için bir CountDownTimer kullandığımızda veya bir nitelik animasyon efekti var mı?

İşlevi etkilemeden geri sayımı / animasyonu ne zaman iptal edebilirim (kullanıcının görünür aralığına kaydırın, geri sayım / animasyon normal çalışıyor)?

OnBindViewHolder ile yazışmanın herhangi bir yolu var mı? Tıpkı onAttachedToWindow, onDetachedFromWindow gibi.

Cevap:

OnAttachedToWindow ve onDetachedFromWindow RecyclerView'da hala uygulanabilir mi?

RecyclerView'da, bu iki Öğe yöntemi [ilk görünüm] ve [ekrandan tamamen dışarı kaydırıldığında] (yani ekranda tamamen görünmez olduğunda) geri çağrılacaktır (aynı addaki yöntem ayrıca ViewHolder'ı izlemek için Adaptörde geçersiz kılınabilir) Görünme ve kaybolma).

Uygun olup olmadığına gelince, listedeki video oynatma gibi belirli gereksinimlere bağlıdır ve onDetachedFromWindow geri araması yapıldığında duraklatmak / durdurmak mantıklıdır.

Ancak başlıkta belirtilen geri sayım ve öznitelik animasyon efektleri uygun değil Neden?

RecyclerView'ın geri dönüşüm mekanizmasını kısaca gözden geçirelim:

RecyclerView, düzen sırasında bazı uygun ViewHolders'ları geri dönüştürür (doğal kaydırma aslında alt Görünümlerin tekrarlanan düzenidir). ViewHolder'ın durumuna göre geçici olarak nerede saklanacağına karar verir ve bu geçici olarak depolanan ViewHolder koleksiyonlarını iki tür olarak ele alır:

OnBindViewHolder (mAttachedScrap, mCachedViews) aracılığıyla doğrudan yeniden kullanılabilir;

Verileri onBindViewHolder (mRecyclerPool.mScrap) aracılığıyla yeniden bağlama gerekiyor;

mAttachedScrap, normal şartlar altında, RecyclerView her yerleştirildiğinde kullanılacaktır: alt görünümleri yerleştirirken, alt görünümlerin tüm sahipleri geçici olarak ona yerleştirilecektir.Her alt görünümün yeni konumunu hesapladıktan sonra, Bunları mAttachedScrap'ten birer birer çıkarın, elbette hepsi çıkarılmayacaktır, çünkü bazı eski öğeler bu düzende ekrandan tamamen kaymış olabilir.

Peki, mAttachedScrap'te bırakılan ve çıkarılmayan ViewHolders'a ne olur?

Normal koşullar altında, mCachedViews'a atılırlar (mCachedViews'tan çıkarıldığında verileri yeniden bağlama gerekmediğini, yani onBindViewHolder yönteminden geçmeyeceklerini unutmayın).

Öğe tamamen ekrandan dışarı kaydırıldığında, Adaptörün onDetachedFromWindow ve Item's onDetachedFromWindow geri çağrılacağını söyledim. Yani onDetachedFromWindow geri çağrıldığında ViewHolder gerçekten geri dönüştürülmez! Geri sayımı / animasyonu bu anda iptal ederseniz, ekranda tekrar göründüklerinde hareket etmeyeceklerdir, çünkü doğrudan yeniden kullanılırlar ve veriler geri tepmez.

Ne zaman iptal edilmelidir?

Var onView Geri Dönüştürülmüş Yöntem, isme bakın, Öğe geri dönüştürüldüğünde geri çağrıldığını biliyorsunuz. . .

Doğru, bu yöntem geri çağrıldığında, bu Tutucu mRecyclerPool.mScrap'e atılmış demektir, yani tekrar çıkarıldığında, verileri onBindViewHolder yöntemi aracılığıyla yeniden bağlayacaktır.

Geri sayım / animasyon burada iptal edilirse, tamamen iyidir (ancak bir dahaki sefere devam edebilmek için mevcut ilerlemeyi kaydetmeyi unutmayın).

Dolayısıyla onBindViewHolder'a karşılık gelen yöntem bu onViewRecycled'dir.

Son olarak, yukarıdaki açıklamanın çok titiz olduğu garanti edilemez, bu yüzden lütfen öğrenerek ve eleştirel bir tavırla çalışın Herhangi bir sorununuz varsa, lütfen mümkün olduğunca teknik noktaları belirtin ve birlikte ilerleyin.

Sonunda

Son olarak şunu söylemek istiyorum: Programcılar için öğrenilmesi gereken çok fazla bilgi içeriği ve teknoloji var. Çevre tarafından ortadan kaldırılmak istemiyorsanız, kendinizi sürekli geliştirmelisiniz. Bize uyum sağlamak için çevreye değil, her zaman çevreye uyum sağlıyoruz!

İşte yukarıdaki teknik sistem şemasıyla ilgili düzinelerce set Tencent, Toutiao, Ali, Meituan ve diğer şirketlerden 19 yıl içinde mülakat soruları , Teknik noktaları video ve PDF olarak düzenledi (aslında beklenenden çok daha fazla enerji harcadı), Bilgi bağlamı + birçok ayrıntı , Sınırlı alan nedeniyle, işte resim şeklinde bir parçası.

Size birçok kazanç getireceğine inanıyorum:

[Android gelişmiş öğrenme videosu], [Android mülakat hilelerinin tam seti PDF], [Android geliştirme temel bilgi notları] özel mesajla [Android] ücretsiz olarak elde edilebilir!

Programcı olmak kolaydır. İyi bir programcı olmak sürekli öğrenmeyi gerektirir. Genç programcıdan kıdemli programcıya, küçük mimardan kıdemli mimara veya yönetime, teknik müdürden teknik direktörlüğe kadar her aşamada Farklı yeteneklere hakim olmanız gerekiyor. İşinizde ve yetenek gelişiminizde akranlarınızdan kurtulmak için kariyer yönünüzü erkenden belirleyin.

Android geliştiricilerinin zorlu yolculuğunu geri sayın: o yıllarda hepimizin yaptığı hatalar
önceki
Görüşme sırasında hangi konulara dikkat edilmelidir? İşte programcı iş görüşmelerinin 66 detayı
Sonraki
Android röportajları için temel bilgi noktaları: Android'de Handler hakkında sekiz önemli sorunun bir özeti
Yıl ortasında Ali'ye tekrar katılmak için iyi bir zaman, Ali'ye katılmak istersem ne yapmalıyım?
Android programcıları: İyi bir iş bulmak ve salgın krizi kırmak için mülakata nasıl hazırlanılır?
"Bir günde röportaj için nasıl hazırlandım ve Tencent teklifini nasıl aldım?"
Muhabir: Temel java nasıl? Çok iş parçacıklı okuma mutlaka çok iş parçacıklı güvenlik sorunlarına neden olur mu?
Yılbaşı tarım ürünleri siparişleri 200 milyonu aştı, Pinduoduo markalı tarım ürünlerini şehirlere ve kırsal alanlara tanıtıyor
Didi, 62 tren istasyonunda çevrimiçi araç çağırma için özel toplama noktaları ve kanallar oluşturuyor
Marka yükseltme ve geliştirme Wanrun Group, 2020'de yeni bir sayfa açıyor
Yeni Land Rover Discovery Sport neden Discovery ailesinin spor şampiyonu oldu?
Ağır! Chengdu: İlkokul 13 Nisan'da başlıyor! Lise giriş sınavı orta derecede gecikti
Uzman ve malzeme gönderen Çin, bunun gibi Asyalı kardeşleri destekliyor
"Herhangi bir zorlukla karşılaşırsanız, kırmızı yeleği bulun!" - Wanjia'nın ışıklarını kalpleriyle yakarlar
To Top