Android - Установка таймаута для AsyncTask?
У меня есть 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
запускается новый обработчик, который отменяет AsyncTask
через 30 секунд, если он все еще работает.
Это хороший подход? Или есть что-то встроенное в AsyncTask
что лучше для этого подходит?
7 ответов
Да, есть AsyncTask.get()
myDownloader.get(30000, TimeUnit.MILLISECONDS);
Обратите внимание, что вызов этого в основном потоке (поток AKA. UI) заблокирует выполнение, вам, вероятно, потребуется вызвать его в отдельном потоке.
Используйте класс CountDownTimer в стороне от расширенного класса для AsyncTask в методе onPreExecute():
Главное преимущество, асинхронный мониторинг осуществляется внутри класса.
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), и он вызовет onTick() 6 раз перед вызовом onFinish(). Это хорошо, если вы хотите добавить мониторинг.
Спасибо за все полезные советы, которые я получил на этой странице:-)
В этом случае ваш загрузчик основан на соединении URL, у вас есть ряд параметров, которые могут помочь вам определить время ожидания без сложного кода:
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(15000);
urlc.setReadTimeout(15000);
Если вы просто добавите этот код в асинхронную задачу, все в порядке.
"Тайм-аут чтения" предназначен для проверки неисправной сети на протяжении всей передачи.
"Время ожидания подключения" вызывается только в начале, чтобы проверить, работает ли сервер или нет.
Я не думаю, что есть что-то подобное, встроенное в AsyncTask. Ваш подход, кажется, хороший. Обязательно периодически проверяйте значение isCancelled() в методе doInBackground вашего AsyncTask, чтобы завершить этот метод, как только поток пользовательского интерфейса отменит его.
Если по какой-то причине вы хотите избежать использования обработчика, вы можете периодически проверять System.currentTimeMillis в AsyncTask и выходить по таймауту, хотя мне больше нравится ваше решение, поскольку оно может фактически прервать поток.
Вдохновляясь вопросом, я написал метод, который выполняет некоторую фоновую задачу через 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;
}
Вы можете поставить еще одно условие, чтобы сделать отмену более надежной. например,
if (downloader.getStatus() == AsyncTask.Status.RUNNING || downloader.getStatus() == AsyncTask.Status.PENDING)
downloader.cancel(true);
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();
}