Android - Bir AsyncTask için Zaman Aşımı Ayarlama?


125

AsyncTaskBir web sitesinden büyük bir veri listesi indiren yürüttüğüm bir sınıfım var.

Son kullanıcının kullanım sırasında çok yavaş veya kesintili bir veri bağlantısına sahip olması durumunda, AsyncTaskzaman aşımını bir süre sonra yapmak istiyorum . Buna ilk yaklaşımım şöyle:

MyDownloader downloader = new MyDownloader();
downloader.execute();
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
  @Override
  public void run() {
      if ( downloader.getStatus() == AsyncTask.Status.RUNNING )
          downloader.cancel(true);
  }
}, 30000 );

Başladıktan sonra AsyncTask, AsyncTaskhala çalışıyorsa 30 saniye sonra iptal edecek yeni bir işleyici başlatılır .

Bu iyi bir yaklaşım mı? Yoksa AsyncTaskbu amaca daha uygun yerleşik bir şey var mı?


18
Birkaç farklı yaklaşımı denedikten sonra, sorunuzun kabul edilen cevap olması gerektiği sonucuna vardım.
JohnEye

Aynı soruna gerçekten düştüğüm soru için teşekkürler ve kod
parçanız

1
Sorunuzun kendisi iyi bir cevap +50 :)
karthik kolanji

Yanıtlar:


44

Evet, AsyncTask.get () var

myDownloader.get(30000, TimeUnit.MILLISECONDS);

Bunu ana iş parçacığında (AKA. UI iş parçacığı) çağırmanın yürütmeyi engelleyeceğini unutmayın, muhtemelen onu ayrı bir iş parçacığında çağırmanız gerekir.


9
Görünüşe göre, bu zaman aşımı yöntemi ana UI iş parçacığında çalışıyorsa, AsyncTask kullanma amacını ortadan kaldırıyor gibi görünüyor ... Neden sorumda açıkladığım handleryaklaşımı kullanmıyorsunuz ? Handler's Runnable'ı çalıştırmayı beklerken UI iş parçacığı donmadığı için çok daha basit görünüyor ...
Jake Wilson

Tamam teşekkürler, bunu yapmanın uygun bir yolu olup olmadığından emin değildim.
Jake Wilson

3
Başka bir ileti dizisinde neden get () işlevini çağırdığını anlamıyorum. Garip görünüyor çünkü AsyncTask'ın kendisi bir tür iş parçacığı. Jakobud'un çözümünün daha iyi olduğunu düşünüyorum.
emeraldhieu

Bence .get () posix thread'in join ile benzer, burada amaç iş parçacığının tamamlanmasını beklemek. Sizin durumunuzda, koşullu bir özellik olan bir zaman aşımı olarak hizmet eder. Bu nedenle, ana kullanıcı arayüzünün engellenmesini önlemek için işleyiciden veya başka bir iş parçacığından .get () 'i çağırmanız gerekir
Constantine Samoilenko

2
Bunun yıllar sonra olduğunu biliyorum, ancak bu hala android'de yerleşik değil, bu yüzden bir destek sınıfı yaptım. Umarım birine yardım eder. gist.github.com/scottTomaszewski/…
Scott Tomaszewski

20

İndiriciniz bir URL bağlantısına dayanıyorsa, karmaşık kod olmadan bir zaman aşımı tanımlamanıza yardımcı olabilecek bir dizi parametreniz vardır:

  HttpURLConnection urlc = (HttpURLConnection) url.openConnection();

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

Bu kodu sadece eşzamansız görevinize getirirseniz, sorun değil.

'Okuma Zaman Aşımı', aktarım boyunca kötü bir ağı test etmek içindir.

'Bağlantı Zaman Aşımı' yalnızca başlangıçta sunucunun çalışıp çalışmadığını test etmek için çağrılır.


1
Bir anlaşmadayım. Bu yaklaşımı kullanmak daha basittir ve zaman aşımına ulaşıldığında bağlantıyı gerçekten sonlandırır. AsyncTask.get () yaklaşımını kullanarak, yalnızca zaman sınırına ulaşıldığı, ancak indirme işleminin hala devam ettiği ve aslında daha sonra tamamlanabileceğinden, kodda daha fazla karmaşıklığa neden olduğu konusunda bilgilendirilirsiniz. Teşekkürler.
sersemlemiş

Çok yavaş internet bağlantılarında çok sayıda iş parçacığı kullanırken bunun yeterli olmadığını lütfen unutmayın. Daha fazla bilgi: leakfromjavaheap.blogspot.nl/2013/12/… ve thushw.blogspot.nl/2010/10/…
Kapitein Witbaard

20

OnPreExecute () yönteminde AsyncTask için genişletilmiş sınıfın yanında CountDownTimer Sınıfını kullanın:

Ana avantaj, Async izleme sınıfta dahili olarak yapılır.

public class YouExtendedClass extends AsyncTask<String,Integer,String> {
...
public YouExtendedClass asyncObject;   // as CountDownTimer has similar method -> to prevent shadowing
...
@Override
protected void onPreExecute() {
    asyncObject = this;
    new CountDownTimer(7000, 7000) {
        public void onTick(long millisUntilFinished) {
            // You can monitor the progress here as well by changing the onTick() time
        }
        public void onFinish() {
            // stop async task if not in progress
            if (asyncObject.getStatus() == AsyncTask.Status.RUNNING) {
                asyncObject.cancel(false);
                // Add any specific task you wish to do as your extended class variable works here as well.
            }
        }
    }.start();
...

Örneğin CountDownTimer (7000, 7000) -> CountDownTimer (7000, 1000) 'i değiştirin ve onFinish ()' i çağırmadan önce 6 kez onTick () 'i çağıracaktır. Biraz izleme eklemek istiyorsanız bu iyidir.

Bu sayfada aldığım tüm iyi tavsiyeler için teşekkürler :-)


2

AsyncTask'ta böyle bir şeyin yerleşik olduğunu sanmıyorum. Yaklaşımınız iyi görünüyor. UI iş parçacığı iptal ettikten sonra bu yöntemi sonlandırmak için AsyncTask'ınızın doInBackground yöntemindeki isCancelled () değerini periyodik olarak kontrol ettiğinizden emin olun.

İşleyiciyi herhangi bir nedenle kullanmaktan kaçınmak istiyorsanız, AsyncTask'ınızda System.currentTimeMillis'i periyodik olarak kontrol edebilir ve zaman aşımından çıkabilirsiniz, ancak çözümünüzü gerçekten iş parçacığını kesebileceği için daha çok beğeniyorum.


0
         Context mContext;

         @Override
         protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
                                    mContext = this;

            //async task
            final RunTask tsk = new RunTask (); 
            tsk.execute();

            //setting timeout thread for async task
            Thread thread1 = new Thread(){
            public void run(){
                try {
                    tsk.get(30000, TimeUnit.MILLISECONDS);  //set time in milisecond(in this timeout is 30 seconds

                } catch (Exception e) {
                    tsk.cancel(true);                           
                    ((Activity) mContext).runOnUiThread(new Runnable()
                    {
                         @SuppressLint("ShowToast")
                        public void run()
                         {
                            Toast.makeText(mContext, "Time Out.", Toast.LENGTH_LONG).show();
                            finish(); //will close the current activity comment if you don't want to close current activity.                                
                         }
                    });
                }
            }
        };
        thread1.start();

         }

2
Bazı açıklamalar da eklemeyi düşünün
Saif Asif

0

İptali daha sağlam hale getirmek için bir koşul daha koyabilirsiniz. Örneğin,

 if (downloader.getStatus() == AsyncTask.Status.RUNNING || downloader.getStatus() == AsyncTask.Status.PENDING)
     downloader.cancel(true);

0

Sorudan esinlenerek, AsyncTask aracılığıyla bazı arka plan görevlerini gerçekleştiren bir yöntem yazdım ve işlem, LOADING_TIMEOUT'tan daha uzun sürerse, yeniden denenecek bir uyarı diyaloğu görünecektir.

public void loadData()
    {
        final Load loadUserList=new Load();
        loadUserList.execute();
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (loadUserList.getStatus() == AsyncTask.Status.RUNNING) {
                    loadUserList.cancel(true);
                    pDialog.cancel();
                    new AlertDialog.Builder(UserList.this)
                            .setTitle("Error..!")
                            .setMessage("Sorry you dont have proper net connectivity..!\nCheck your internet settings or retry.")
                            .setCancelable(false)
                            .setPositiveButton("Retry", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    loadData();
                                }
                            })
                            .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                                @Override


                      public void onClick(DialogInterface dialogInterface, int i) {
                                System.exit(0);
                            }
                        })
                        .show();
            }
        }
    }, LOADING_TIMEOUT);
    return;
}
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.