android 안드로이드 - AsyncTask를 여러 번 실행하십시오.





인터넷 wakelock (6)


ASyncTask의 화재 및 잊어 버린 인스턴스에 대한 이유는 Steve Prentice의 대답에 자세히 설명되어 있습니다. 그러나 ASyncTask를 몇 번이나 실행하도록 제한되어 있지만 스레드가 실행되는 동안 마음껏 자유롭게 할 수 있습니다. .

실행 코드를 doInBackground () 내의 루프 안에 넣고 동시 잠금을 사용하여 각 실행을 트리거하십시오. publishProgress () / onProgressUpdate ()를 사용하여 결과를 검색 할 수 있습니다.

예:

class GetDataFromServerTask extends AsyncTask<Input, Result, Void> {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition tryAgain = lock.newCondition();
    private volatile boolean finished = false;

    @Override
    protected Void doInBackground(Input... params) {

        lock.lockInterruptibly();

        do { 
            // This is the bulk of our task, request the data, and put in "result"
            Result result = ....

            // Return it to the activity thread using publishProgress()
            publishProgress(result);

            // At the end, we acquire a lock that will delay
            // the next execution until runAgain() is called..
            tryAgain.await();

        } while(!finished);

        lock.unlock();
    }

    @Override
    protected void onProgressUpdate(Result... result) 
    {
        // Treat this like onPostExecute(), do something with result

        // This is an example...
        if (result != whatWeWant && userWantsToTryAgain()) {
            runAgain();
        }
    }

    public void runAgain() {
        // Call this to request data from the server again
        tryAgain.signal();
    }

    public void terminateTask() {
        // The task will only finish when we call this method
        finished = true;
        lock.unlock();
    }

    @Override
    protected void onCancelled() {
        // Make sure we clean up if the task is killed
        terminateTask();
    }
}

물론 이것은 ASyncTask의 전통적인 사용법보다 약간 더 복잡하며 실제 진행보고를 위해 publishProgress () 를 사용하지 않습니다 . 그러나 메모리가 걱정된다면이 접근 방식은 런타임시 힙에 하나의 ASyncTask 만 남도록 보장합니다.

내 Activity에서는 AsyncTask와 AsyncTask의 인스턴스 인 매개 변수에서 확장되는 클래스를 사용합니다. mInstanceOfAT.execute("") 호출하면 모든 것이 잘됩니다. 하지만 AsyncTask (네트워크 작업이 작동하지 않는 경우)를 다시 호출하는 업데이트 버튼을 누르면 응용 프로그램이 다운됩니다. 원인은 다음과 같은 예외가 나타납니다.

작업을 실행할 수 없습니다 : 작업이 이미 실행되었습니다 (작업은 한 번만 실행될 수 있음).

Asyctask의 인스턴스에 대해 cancel (true)을 호출하려고했지만 그 중 하나가 작동하지 않습니다. 지금까지 유일한 해결책은 Asyntask의 새로운 인스턴스를 만드는 것입니다. 그게 올바른 방법일까요?

감사.




나는 같은 문제가 있었다. 내 경우에는 내가 onCreate()onResume( )에서하고 싶은 작업이 있습니다. 그래서 내 Asynctask 정적, 그리고 그것에서 인스턴스를 얻을. 이제 우리에게는 여전히 같은 문제가 있습니다.

그래서 내가 onPostExecute ()에서 한 것은 이것입니다 :

instance = null;

내 인스턴스가 null이 아닌 정적 getInstance 메소드를 체크인했는지 확인합니다. 그렇지 않으면 내가 생성합니다.

if (instance == null){
    instance = new Task();
}
return instance;

postExecute의 메소드는 인스턴스를 비우고 다시 작성합니다. 물론 이것은 수업 외부에서 할 수 있습니다.




그렇습니다. 의사는 하나의 Asyntask 만 실행할 수 있다고 말합니다.

사용할 때마다 다음을 인스턴스화해야합니다.

// Any time if you need to call her
final FirmwareDownload fDownload = new FirmwareDownload();
fDownload.execute("your parameter");

static class FirmwareDownload extends AsyncTask<String, String, String> {
}



회전 작업을 정적으로 만들었습니다. 그런 다음 회전 변경시 ​​UI 스레드에 첨부, 분리 및 다시 첨부 할 수있었습니다. 하지만 귀하의 질문으로 돌아가려면, 내가 무엇 스레드가 실행되고 있는지 확인하기 위해 플래그를 만들 수 있습니다. 스레드를 다시 시작하려면 회전 작업이 실행 중인지 확인한 후 경고를 표시합니다. 그렇지 않은 경우 null로 설정 한 후 새 오류 메시지를 작성합니다. 오류가 표시되면 해결됩니다. 또한, 성공적으로 완료되면 회전 완료 인식 작업이 종료되어 다시 준비가됩니다.




AsyncTask 인스턴스는 한 번만 사용할 수 있습니다.

대신 new MyAsyncTask().execute(""); 와 같이 작업을 호출하십시오 new MyAsyncTask().execute("");

AsyncTask API 문서에서 :

스레딩 규칙

이 클래스가 제대로 작동하려면 몇 가지 스레딩 규칙을 따라야합니다.

  • 타스크 인스턴스는 UI 스레드에서 작성해야합니다.
  • execute (Params ...)는 UI 스레드에서 호출해야합니다.
  • onPreExecute (), onPostExecute (Result), doInBackground (Params ...), onProgressUpdate (Progress ...)를 수동으로 호출하지 마십시오.
  • 작업은 한 번만 실행할 수 있습니다 (두 번째 실행을 시도하면 예외가 throw됩니다).



배경 / 이론

AsyncTask를 사용하면 백그라운드 스레드에서 작업을 실행하면서 결과를 UI 스레드에 게시 할 수 있습니다.

사용자는 항상 앱과 상호 작용할 수 있어야하므로 웹에서 콘텐츠를 다운로드하는 등의 작업으로 기본 (UI) 스레드차단하지 않는 것이 중요 합니다 .

이것이 AsyncTask 사용하는 이유입니다.

실행 가능한 객체와 다른 스레드의 메시지를 보내고 처리 할 수있게 해주는 UI 스레드 메시지 대기열과 처리기를 래핑하여 간단한 인터페이스를 제공 합니다 .

이행

AsyncTask 는 제네릭 클래스입니다. (생성자에서 매개 변수화 된 유형 을 사용합니다.)

세 가지 일반 유형을 사용합니다.

Params - 실행시 작업에 전송되는 매개 변수의 유형입니다.

Progress - 백그라운드 계산 중에 게시 된 진행 단위의 유형입니다.

Result - 백그라운드 계산의 결과 유형입니다.

비동기 작업에서는 모든 유형이 항상 사용되는 것은 아닙니다. 유형을 사용하지 않는 것으로 표시하려면 유형 Void :

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

이 세 매개 변수는 AsyncTask 에서 재정의 할 수있는 세 가지 기본 함수에 해당합니다 .

  • doInBackground(Params...)
  • onProgressUpdate(Progress...)
  • onPostExecute(Result)

AsyncTask를 실행하려면

백그라운드 태스크로 보내지는 매개 변수로 execute() 를 호출하십시오.

무슨 일이야

  1. 기본 / UI 스레드에서 onPreExecute() 가 호출됩니다. (사용자 인터페이스에서 진행률 표시 줄과 같이이 스레드에서 초기화하려면)

  2. 백그라운드 스레드에서 doInBackground(Params...) 가 호출됩니다. (매개 변수는 Execute 함수에 전달되는 매개 변수입니다.)

    • 장기간 실행해야하는 작업

    • AsyncTask를 사용하려면 적어도 doInBackground() 를 대체해야합니다.

    • 백그라운드 계산이 아직 실행 중일 때 publishProgress(Progress...) 를 호출하여 사용자 인터페이스의 진행 상태 표시를 업데이트합니다. (예 : 진행률 표시 줄에 애니메이션을 적용하거나 텍스트 필드에 로그를 표시하십시오.)

      • 이로 인해 onProgressUpdate() 가 호출됩니다.
  3. 백그라운드 스레드에서 결과는 doInBackground() 에서 리턴됩니다. 그러면 다음 단계가 시작됩니다.

  4. 기본 / UI 스레드에서 반환 된 결과와 함께 onPostExecute() 호출됩니다.

예제들

웹에서 무언가를 다운로드하는 차단 작업의 예를 다시 사용하면,

  • 예제 A 이미지를 다운로드 하여 ImageView에 표시합니다.
  • 예 B는 일부 파일을 다운로드합니다 .

예제 A

doInBackground() 메서드는 이미지를 다운로드하여 BitMap 유형의 객체에 저장합니다. onPostExecute() 메서드는 비트 맵을 가져 와서 ImageView에 배치합니다.

class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bitImage;

    public DownloadImageTask(ImageView bitImage) {
        this.bitImage = bitImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mBmp = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mBmp = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mBmp;
    }

    protected void onPostExecute(Bitmap result) {
        bitImage.setImageBitmap(result);
    }
}

보기 B

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

예제 B 실행

new DownloadFilesTask().execute(url1, url2, url3);




android android-asynctask