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

를 시작한 후 AsyncTask새 핸들러가 시작되어 AsyncTask아직 실행중인 경우 30 초 후에 취소 됩니다.

이것이 좋은 접근 방식입니까? 아니면 AsyncTask이 목적에 더 적합한 것이 내장되어 있습니까?


18
여러 가지 접근 방식을 시도한 후 귀하의 질문이 허용되는 답변이어야한다는 결론을 내 렸습니다.
JohnEye

질문 해 주셔서 감사합니다. 제가 정말 같은 문제에 빠졌고 귀하의 코드가 도움이되었습니다 +1
Ahmad Dwaik 'Warlock'Oct

1
귀하의 질문은 좋은 답변 +50 : 자체
KARTHIK kolanji

답변:


44

예, AsyncTask.get ()이 있습니다.

myDownloader.get(30000, TimeUnit.MILLISECONDS);

주 스레드 (일명 UI 스레드)에서 이것을 호출하면 실행이 차단되므로 별도의 스레드에서 호출해야 할 수 있습니다.


9
이 시간 제한 메서드가 기본 UI 스레드에서 실행되는 경우 AsyncTask를 사용하는 목적을 무너 뜨리는 것 같습니다 handler. 제 질문에서 설명 하는 접근 방식을 사용하지 않는 이유는 무엇 입니까? 핸들러의 Runnable를 ... 실행 기다리는 동안 UI 스레드가 동결하지 않기 때문에 훨씬 더 간단 보인다
제이크 윌슨

고마워요. 적절한 방법이 있는지 잘 모르겠습니다.
Jake Wilson

3
다른 스레드에서 get ()을 호출하는 이유를 이해할 수 없습니다. AsyncTask 자체가 일종의 스레드이기 때문에 이상하게 보입니다. Jakobud의 솔루션이 더 괜찮다고 생각합니다.
emeraldhieu

.get ()은 스레드가 완료 될 때까지 기다리는 것이 목적인 posix 스레드의 조인과 유사하다고 생각합니다. 귀하의 경우에는 상황에 따른 속성 인 시간 제한으로 사용됩니다. 당신이 차단 메인 UI 방지하기 위해 핸들러 또는 다른 스레드에서 () 갔지를 호출해야하는 이유의 그
콘스탄틴 Samoilenko

2
나는 이것이 몇 년 후라는 것을 알고 있지만 이것은 여전히 ​​안드로이드에 내장되어 있지 않으므로 지원 클래스를 만들었습니다. 누군가에게 도움이되기를 바랍니다. 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/… and Thushw.blogspot.nl/2010/10/…
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
뿐만 아니라 몇 가지 설명을 추가하는 것을 고려
사이프 아시프에게

0

취소를 더욱 강력하게 만들기 위해 조건을 하나 더 추가 할 수 있습니다. 예 :

 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.