Android-AsyncTaskのタイムアウトの設定?


125

私が持っているAsyncTask、私はそれのダウンロードにウェブサイトからのデータの大きなリストを実行するクラスを。

使用時にエンドユーザーのデータ接続が非常に遅いか、むらがある場合は、一定時間AsyncTask後にタイムアウトを設定します。これに対する私の最初のアプローチはそうです:

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 );

を開始した後、まだ実行されている場合、30秒後にAsyncTaskをキャンセルする新しいハンドラが開始されますAsyncTask

これは良いアプローチですか?それともAsyncTask、この目的により適したものが組み込まれていますか?


18
いくつかの異なるアプローチを試みた後、私はあなたの質問が受け入れられる答えであるべきであると結論しました。
JohnEye

私は本当に同じ問題に陥り、あなたのコードが私を助けてくれた質問に感謝します
Ahmad Dwaik 'Warlock'

1
あなたの質問はそれ自体が良い答えです+50 :)
karthik kolanji

回答:


44

はい、AsyncTask.get()があります

myDownloader.get(30000, TimeUnit.MILLISECONDS);

これをメインスレッド(AKA UIスレッド)で呼び出すと、実行がブロックされます。おそらく、別のスレッドで呼び出す必要があります。


9
このタイムアウトメソッドがメインUIスレッドで実行される場合、最初にAsyncTaskを使用する目的に反するようです... handler質問で説明するアプローチを使用しないのはなぜですか?ハンドラーのRunnableの実行を待機している間、UIスレッドがフリーズしないため、はるかに簡単に思われます...
ジェイクウィルソン

わかりました。ありがとうございます。それを行う適切な方法があるかどうかわかりませんでした。
Jake Wilson

3
別のスレッドでget()を呼び出す理由がわかりません。AsyncTask自体が一種のスレッドであるため、奇妙に見えます。ヤコブドの解決策はもっといいと思います。
emeraldhieu 2012

.get()は、スレッドが完了するのを待つことが目的のposixスレッドの結合に似ていると思います。あなたの場合、それはタイムアウトとして機能します。これは状況プロパティです。あなたがブロックし、メインUI避けるために、ハンドラから、または別のスレッドから()に.get呼び出す必要が理由だということ
コンスタンティンSamoilenko

2
これは数年後のことですが、これはまだAndroidに組み込まれていないため、サポートクラスを作成しました。誰かのお役に立てば幸いです。gist.github.com/scottTomaszewski/…–
Scott Tomaszewski

20

この場合、ダウンローダーはURL接続に基づいており、複雑なコードなしでタイムアウトを定義するのに役立ついくつかのパラメーターがあります。

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

  urlc.setConnectTimeout(15000);

  urlc.setReadTimeout(15000);

このコードを非同期タスクに取り込むだけで問題ありません。

「読み取りタイムアウト」は、転送全体にわたって不良ネットワークをテストすることです。

「接続タイムアウト」は、サーバーが起動しているかどうかをテストするために最初にのみ呼び出されます。


1
私は同意します。このアプローチの方が簡単で、タイムアウトに達すると実際に接続を終了します。AsyncTask.get()アプローチを使用すると、制限時間に達したことが通知されるだけですが、ダウンロードはまだ処理中であり、後で実際に完了する可能性があります。コードがさらに複雑になります。ありがとう。
ボーッ

非常に遅いインターネット接続で多くのスレッドを使用する場合、これでは不十分であることに注意してください。詳細情報:leakfromjavaheap.blogspot.nl/2013/12/…そして、hw.blogspot.nl
Kapitein Witbaard

20

onPreExecute()メソッドのAsyncTaskの拡張クラスでCountDownTimerクラスを使用します。

主な利点は、クラスの内部で行われる非同期監視です。

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();
...

たとえば、CountDownTimer(7000、7000)-> CountDownTimer(7000、1000)を変更すると、onFinish()を呼び出す前にonTick()が6回呼び出されます。これは、監視を追加する場合に適しています。

私がこのページで得たすべての良いアドバイスをありがとう:-)


2

AsyncTaskに組み込まれているようなものはないと思います。あなたのアプローチは良いもののようです。AsyncTaskのdoInBackgroundメソッドでisCancelled()の値を定期的に確認し、UIスレッドがキャンセルするとこのメソッドを終了するようにしてください。

何らかの理由でハンドラーの使用を避けたい場合は、AsyncTask内で定期的にSystem.currentTimeMillisをチェックしてタイムアウトで終了することができますが、実際にはスレッドを中断できるため、ソリューションの方が好きです。


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
いくつかの説明も追加することを検討してください
Saif Asif

0

条件をもう1つ置くと、キャンセルをより堅牢にすることができます。例えば、

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

0

質問から発想を得て、AsyncTaskを介してバックグラウンドタスクを実行するメソッドを記述しました。処理にLOADING_TIMEOUT以上かかる場合は、再試行する警告ダイアログが表示されます。

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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.