Webサイトからデータの大きなリストをダウンロードする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 );
AsyncTask
を開始した後、30秒後にAsyncTask
がまだ実行されている場合はキャンセルする新しいハンドラーが開始されます。
これは良いアプローチですか?または、この目的により適したAsyncTask
に組み込まれているものはありますか?
はい、あります AsyncTask.get()
myDownloader.get(30000, TimeUnit.MILLISECONDS);
これをメインスレッド(別名UIスレッド)で呼び出すと実行がブロックされることに注意してください。おそらく、別のスレッドで呼び出す必要があります。
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回呼び出します。これは、監視を追加する場合に適しています。
このページで得たすべての良いアドバイスをありがとう:-)
この場合、ダウンローダーはURL接続に基づいており、複雑なコードなしでタイムアウトを定義するのに役立つ多くのパラメーターがあります。
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(15000);
urlc.setReadTimeout(15000);
このコードを非同期タスクに組み込むだけであれば、問題ありません。
「読み取りタイムアウト」は、転送中に不良ネットワークをテストすることです。
「接続タイムアウト」は、サーバーが起動しているかどうかをテストするために最初にのみ呼び出されます。
AsyncTaskに組み込まれているようなものはないと思います。あなたのアプローチは良いもののようです。 AsyncTaskのdoInBackgroundメソッドでisCancelled()の値を定期的にチェックして、UIスレッドがキャンセルしたらこのメソッドを終了するようにしてください。
何らかの理由でハンドラーの使用を避けたい場合は、AsyncTask内でSystem.currentTimeMillisを定期的に確認し、タイムアウト時に終了できますが、実際にスレッドを中断できるため、ソリューションの方が好きです。
質問からインスピレーションを得て、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;
}
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();
}
キャンセルをより堅牢にするために、もう1つの条件を追加できます。例えば。、
if (downloader.getStatus() == AsyncTask.Status.RUNNING || downloader.getStatus() == AsyncTask.Status.PENDING)
downloader.cancel(true);