AsyncTask Android 예제

에 대해 읽고 있었고 AsyncTask아래 간단한 프로그램을 시도했습니다. 그러나 작동하지 않는 것 같습니다. 어떻게 작동시킬 수 있습니까?

public class AsyncTaskActivity extends Activity {

    Button btn;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn = (Button) findViewById(R.id.button1);
        btn.setOnClickListener((OnClickListener) this);
    }

    public void onClick(View view){
        new LongOperation().execute("");
    }

    private class LongOperation extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<5;i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed");
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

백그라운드 프로세스에서 5 초 후에 레이블을 변경하려고합니다.

이것은 내 main.xml입니다 .

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="10"
        android:padding="10dip">
    </ProgressBar>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Progress" >
    </Button>
    <TextView android:id="@+id/output"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Replace"/>
</LinearLayout>



답변

좋아, 다른 스레드를 통해 GUI에 액세스하려고합니다. 이것은 기본적으로 좋은 습관이 아닙니다.

AsyncTask doInBackground()는 다른 스레드 내부의 모든 것을 실행 하며 뷰가있는 GUI에 액세스 할 수 없습니다.

preExecute()그리고 postExecute()당신은 이전과 무거운이 새로운 스레드에서 발생한 후 GUI에 대한 액세스를 제공하며, 당신도 할 수 긴 작업의 결과를 전달할 수있는 postExecute()후 처리의 결과를 표시합니다.

나중에 TextView를 업데이트하는 다음 행을 참조하십시오.

TextView txt = findViewById(R.id.output);
txt.setText("Executed");

에 넣으십시오 onPostExecute().

그러면 doInBackground완료 후 TextView 텍스트가 업데이트 된 것을 볼 수 있습니다 .

onClick 리스너가 선택된보기를 확인하지 않는 것으로 나타났습니다. 가장 쉬운 방법은 switch 문을 사용하는 것입니다. 혼란을 피하기 위해 모든 제안 사항을 아래에서 편집 한 완전한 수업이 있습니다.

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity implements OnClickListener {

    Button btn;
    AsyncTask<?, ?, ?> runningTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = findViewById(R.id.button1);

        // Because we implement OnClickListener, we only
        // have to pass "this" (much easier)
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        // Detect the view that was "clicked"
        switch (view.getId()) {
        case R.id.button1:
            if (runningTask != null)
                runningTask.cancel(true);
            runningTask = new LongOperation();
            runningTask.execute();
            break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Cancel running task(s) to avoid memory leaks
        if (runningTask != null)
            runningTask.cancel(true);
    }

    private final class LongOperation extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // We were cancelled; stop sleeping!
                }
            }
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed"); // txt.setText(result);
            // You might want to change "executed" for the returned string
            // passed into onPostExecute(), but that is up to you
        }
    }
}


답변

전체 답변은 여기 이지만이 페이지의 다른 답변을 보완하는 설명 이미지가 있습니다. 저에게 모든 변수가 어디로 가고 있는지 이해하는 것이 처음에는 가장 혼란스러운 부분이었습니다.

여기에 이미지 설명을 입력하십시오


답변

제대로 실행되고 있다고 확신하지만 백그라운드 스레드에서 UI 요소를 변경하려고 시도하지만 그렇지 않습니다.

다음과 같이 호출 및 AsyncTask를 수정하십시오.

호출 클래스

참고 : 개인적 onPostExecute()으로 AsyncTask 자체를 확장하는 클래스가 아닌 AsyncTask 스레드를 실행할 때마다 사용하는 것이 좋습니다 . 결과가 약간 다른 여러 위치에서 AsyncTask가 필요한 경우 특히 코드를 쉽게 읽을 수 있다고 생각합니다.

new LongThread() {
    @Override public void onPostExecute(String result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}.execute("");

LongThread 클래스 (AsyncTask 확장) :

@Override
protected String doInBackground(String... params) {
    for (int i = 0; i < 5; i++) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    return "Executed";
}      


답변

개념과 코드는 여기

Android의 AsyncTask를 사용하는 간단한 예를 만들었습니다. onPreExecute(), doInBackground(), publishProgress()마지막으로 시작합니다 onProgressUpdate().

여기서 doInBackground ()는 백그라운드 스레드로 작동하고 다른 스레드는 UI 스레드에서 작동합니다. doInBackground ()에서 UI 요소에 액세스 할 수 없습니다. 순서는 내가 언급 한 것과 같습니다.

당신이에서 어떤 위젯을 업데이트해야 할 경우에는 doInBackground, 당신은 할 수 publishProgress에서 doInBackground어떤 호출 onProgressUpdate하여 UI 위젯을 업데이트 할 수 있습니다.

class TestAsync extends AsyncTask<Void, Integer, String> {
    String TAG = getClass().getSimpleName();

    protected void onPreExecute() {
        super.onPreExecute();
        Log.d(TAG + " PreExceute","On pre Exceute......");
    }

    protected String doInBackground(Void...arg0) {
        Log.d(TAG + " DoINBackGround", "On doInBackground...");

        for (int i=0; i<10; i++){
            Integer in = new Integer(i);
            publishProgress(i);
        }
        return "You are at PostExecute";
    }

    protected void onProgressUpdate(Integer...a) {
        super.onProgressUpdate(a);
        Log.d(TAG + " onProgressUpdate", "You are in progress update ... " + a[0]);
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.d(TAG + " onPostExecute", "" + result);
    }
}

당신의 활동에서 이것을 다음과 같이 부르십시오 :

new TestAsync().execute();

여기 개발자 참조


답변

이 두 줄을 이동하십시오.

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

AsyncTask의 doInBackground메소드에서 벗어나 메소드에 넣으십시오 onPostExecute. 당신 AsyncTask은 다음과 같이 보일 것입니다 :

private class LongOperation extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        try {
            Thread.sleep(5000); // no need for a loop
        } catch (InterruptedException e) {
            Log.e("LongOperation", "Interrupted", e);
            return "Interrupted";
        }
        return "Executed";
    }

    @Override
    protected void onPostExecute(String result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}


답변

배경 / 이론

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. A의 백그라운드 스레드 , doInBackground(Params...)라고합니다.

    • ( Params을 통해 전달되었습니다 execute.)
    • 장기 실행 작업이 발생하는 위치
    • doInBackground()AsyncTask를 사용하려면 최소한 재정의해야합니다 .

    • publishProgress(Progress...)백그라운드 계산이 여전히 실행되는 동안 진행률 표시 (예 : UI 애니메이션 또는 로그 텍스트 인쇄)로 사용자 인터페이스를 업데이트하려면 호출하십시오 .

      • 원인은 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);


답변

비동기 작업이 실행될 때 작업은 다음 4 단계를 거칩니다.

  1. onPreExecute ()
  2. doInBackground (파람 …)
  3. onProgressUpdate (진행 …)
  4. onPostExecute (결과)

아래는 데모 예입니다.

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

그리고 일단 생성하면 작업이 매우 간단하게 실행됩니다.

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