Kullanıcı arayüzündeki ilerlemeyi bildirmek için en iyi strateji - geri arama nasıl gerçekleşmelidir?


11

Bazen kullanıcı yürütülmesi biraz zaman alan genişletilmiş bir teknik işlem başlatır. Bu durumlarda, şu anda hangi görevin yürütüldüğüne ilişkin bilgilerle birlikte, bir tür ilerleme çubuğu görüntülemek genellikle iyidir.

Kullanıcı arayüzünün ve mantık katmanlarının birbirine bağlanmasını önlemek için iletişimin bir tür proxy üzerinden gerçekleşmesi genellikle en iyisidir. Yani, arka uç kendi UI öğelerini manipüle etmemeli, hatta ara katmanla doğrudan etkileşime girmemelidir.

Açıkçası, bu işi yapabilmek için bir yerde bir geri arama olmalı. Genellikle iki yoldan biriyle uyguladım:

  1. Değişken bir nesneyi arka uca iletin ve arka ucun ilerledikçe nesnede değişiklik yapmasını sağlayın. Bir değişiklik meydana geldiğinde nesne ön uca bildirir.

  2. Formun void f(ProgressObject)veya ProgressObject -> unitarka ucun çağırdığı bir geri arama işlevini iletme. Bu durumda, arka uç oluşturur ProgressObjectve tamamen pasiftir. Her ilerlemeyi rapor etmek istediğinde yeni bir nesne inşa etmesi gerektiğini düşünüyorum.

Bu yöntemlerin dezavantajları ve avantajları nelerdir? Üzerinde anlaşmaya varılmış en iyi yöntem var mı? Kullanımları için farklı koşullar var mı?

Göz ardı ettiğim ilerlemeyi bildirmek için tamamen farklı teknikler var mı?


1
Değişmez ve değişmez ile ilgili olarak, avantajlar ve dezavantajlar başka herhangi bir yerdekiyle aynıdır. İlerleme nesnesiyle ilgili olarak, bu çok hafif olabilir; tek bir sayı kadar basit olabilir: yüzde.
Robert Harvey

@RobertHarvey İlerleme nesnesinin boyutu genellikle kullanıcı arayüzü gereksinimlerine bağlıdır. Örneğin Windows kopyalama iletişim kutusuna bakın. Çok fazla bilgi gerektirdiğini düşünüyorum.
GregRos

1
@RobertHarvey Bu benim için bir haber. Bu ne?
GregRos

1
Isıracağım. Biz kullanmak BackgroundWorkerRH söz ettiği. "İlerleme formu" vb. İle birlikte özel bir sınıfa sarılır ve BackgroundWorkertasarımın ayrı bir iş parçacığında çalıştığı gibi bir istisnayı iletmek için basit bir mekanizma . Özelliklerini .Net tarafından önerilen bir şekilde kullandığımız sürece bunun deyimsel olduğu söylenebilir. Ve herhangi bir dil / çerçeve bağlamında "deyimsel" en iyisi olabilir.
radarbob

2
İki yönteminiz arasında önemli bir fark görmüyorum. Ön uçtan arka uca geçen bir nesne, ön ucun bildirilmesine yol açan yöntemler aslında bir geri arama işlevine sahiptir. İkinci yaklaşımınız bilgi aktarmak için az ya da çok karmaşık bir parametre nesnesi kullanıyorsa ya da birkaç basit değer kullanıyorsa, mimari açıdan bir fark yaratmaz. Her iki yaklaşımda da arka uç, ön tarafı aktif olarak bilgilendirir, farklılıklar sadece küçük detaylardır, bu yüzden burada açıklanan farklı bir kavram yoktur.
Doc Brown

Yanıtlar:


8

Değişken bir nesneyi arka uca iletin ve arka ucun ilerledikçe nesnede değişiklik yapmasını sağlayın. Bir değişiklik meydana geldiğinde nesne ön uca bildirir.

Arka uç bu konuda bildirimde bulunursa verimliliği dengelemek zordur. Dikkatsizce, çok düzgün bir ilerleme güncellemesi hedefliyorsanız, ilerlemenizi artırmanın işlemi tamamlamak için gereken süreyi iki katına çıkarır veya üç katına çıkarır.

Arka ucun çağırdığı void f (ProgressObject) veya ProgressObject -> biriminin geri çağrı işlevini iletin. Bu durumda, arka uç ProgressObject öğesini oluşturur ve tamamen pasiftir. Her ilerlemeyi rapor etmek istediğinde yeni bir nesne inşa etmesi gerektiğini düşünüyorum.

Farkı burada bulamıyorum.

Göz ardı ettiğim ilerlemeyi bildirmek için tamamen farklı teknikler var mı?

Arka uçta atomik artışlarla ayrı bir iş parçacığında ön uçtan seçim yapın. Yoklama burada sonlu bir dönemde biten bir operasyon için ve mantıksız bir ilerleme çubuğu hedefliyorsanız, ön uç toplama durumundaki değişikliklerin olasılığı yüksektir. Ön uç iş parçacığından yoklama fikrini sevmiyorsanız koşul değişkenlerini düşünebilirsiniz, ancak bu durumda her bir ayrıntılı ilerleme çubuğu artışını bildirmekten kaçınmak isteyebilirsiniz.


2

Bu, itme ve çekme bildirim mekanizması arasındaki farktır .

Arka uç görevinin bir arka plan / çalışan iş parçacığında yürütülmesini bekliyorsanız, değiştirilebilen nesnenin ( çekme ) kullanıcı arayüzü tarafından tekrarlanabilir şekilde sorgulanması ve senkronize edilmesi gerekir.

Geri arama ( push ), kullanıcı arayüzü için yalnızca bir şey gerçekten değiştiğinde iş oluşturur. Birçok UI çerçevesi, UI iş parçacığında bir parça kodun çalışması için çalışan bir iş parçacığından çağrılabilen bir invokeOnUIThread'e sahiptir, böylece iş parçacığıyla ilgili tehlikelere müdahale etmeden değişiklikleri yapabilirsiniz. (kelime oyunu)

Genel olarak push bildirimleri tercih edilir, çünkü sadece iş yapılması gerektiğinde iş yaparlar.


1
Bence söylediğiniz şey genel olarak doğru. Ancak, bu özel durum için, bir ilerleme çubuğu, değişiklikler hızla meydana gelebilir. Beklentiniz "ilerlemenin" saniyede birçok kez değişme olasılığı varsa, çekme modelini kullanmak daha mantıklıdır, aksi takdirde UI'nin işlemek için çok fazla bildirim almasından endişelenmeniz gerekir.
Robot Gort

Bir ilerleme nesnesini göndermek, kullandığınız bildirim mekanizmasını arka uçtan gizleyebilir, çünkü belki de ilerleme nesnesi geri aramaları yapıyor olabilir. Aslında hatırladığım kadarıyla bir çekme mekanizması kullanmadım ve bunu unuttum: P
GregRos

The mutable object (the pull) will need to be repeatably polled by the UI and synchronized if you expect the back-end task to be executed in a background/worker thread.- Değişken nesne iletişim kutusunun kendisi veya buna çalışan bir arabirim ise değil. Tabii ki, bu zaten bir geri arama anlamına gelir.
Robert Harvey

1
Ha? OP açıkça bir itme mekanizmasının iki farklı biçimini açıklamaktadır, hiçbirinde bir yoklama gerekli değildir.
Doc Brown

0

AngularJS ile websockets kullanıyorum. Ön uç bir mesaj aldığında, birkaç saniye sonra kararması için belirlenen bir mesaj alanında görüntüler. Arka uçta durum mesajlarını bir mesaj kuyruğuna gönderiyorum. Yalnızca metin gönderiyorum, ancak tamamlanma yüzdesi veya aktarım hızı gibi değerlere sahip bir durum nesnesi gönderememe nedenim yok.


0

"İki yolunuzdan" ayrı kavramlarmış gibi bahsettiniz, ama bunu biraz geriye çekmek istiyorum.

  1. Değişken bir nesneyi arka uca iletin ve arka ucun ilerledikçe nesnede değişiklik yapmasını sağlayın. Bir değişiklik meydana geldiğinde nesne ön uca bildirir.

Zaten UI ve mantığın birbirine bağlanmasını önlemek istediğinizi söylediniz, böylece geçtiğiniz bu "değişken nesnenin" aslında mantık modülünde tanımlanan belirli bir arabirimin bir uygulaması olduğunu varsayabilirim. Bu nedenle, bu sadece bir geri aramayı ilerlemeye ilişkin bilgilerle periyodik olarak çağrılan sürece geri aktarmanın başka bir yoludur.

Avantajlar ve dezavantajlar ...

Yöntem (1) için bir dezavantaj, arabirimi uygulayan sınıfın bunu yalnızca bir kez yapabilmesidir. (Farklı çağrılarla farklı işler yapmak istiyorsanız, bir anahtar ifadesine veya ziyaretçi modeline ihtiyacınız olacaktır.) Yöntem (2) ile aynı nesne, arka uç kodunun her çağrılması için farklı bir geri çağrı kullanabilir. değiştirmek.

Yöntem (1) için bir güç, arayüzde çoklu yöntemlere sahip olmanın, yöntemin (2) çoklu geri çağrılarıyla veya çoklu bağlamlar için bir anahtar ifadesiyle tek geri çağrı ile uğraşmaktan çok daha kolay olmasıdır.


-2

Kullanabileceğiniz teknikler çok farklı olabilir.

Farklı bir senaryo ile anlamaya çalışıyorum

  • Db talebi
  • dosyayı indir

Db için basit bir giriş isteği (bir elemt ile db ortalama cevap) bir rapor ilerleme gerekmez ama her zaman ayrı görev ex UI iş parçacığı ateş edebilirsiniz. async veya backgroundworker, burada sonuç için sadece bir geri aramaya ihtiyacınız var.

Peki, tüm envanterinizi 1 milyon öğe ile görmek için sorgularsanız ne olur? Bu sorgunun tamamlanması birkaç dakika sürecektir, bu durumda iş mantığınızdaki perport ilerlemenizi form öğesi / öğeler olarak uygulamanız gerekir, daha sonra kullanıcı arayüzünüzü güncelleyebilirsiniz ve geri aramayı iptal et seçeneği verilebilir.

Dosya indirmek için aynı durum. Burada her zaman ilerleme geri aramanızı bayt bayt biçiminde uygulayabilir ve tüm iletişim denetimini http üzerinde tutabilirsiniz.

Kişisel yaklaşımımda, iş ilerlemesi mantığımı yalnızca müşterilerime uygulayarak başka bir nesneyi uç nokta ile paylaşmaktan kaçınırım.


1
Bu gerçekten avantajlar / dezavantajlar hakkındaki soruya cevap vermez.
Benni
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.