카테고리 보관물: Android

Android

여러 개의 AsyncTask를 동시에 실행하는 것은 불가능합니까?

두 개의 AsyncTask를 동시에 실행하려고합니다. (플랫폼은 Android 1.5, HTC Hero입니다.) 그러나 첫 번째 만 실행됩니다. 다음은 내 문제를 설명하는 간단한 스 니펫입니다.

public class AndroidJunk extends Activity {
 class PrinterTask extends AsyncTask<String, Void, Void> {
     protected Void doInBackground(String ... x) {
      while (true) {
       System.out.println(x[0]);
       try {
        Thread.sleep(1000);
       } catch (InterruptedException ie) {
        ie.printStackTrace();
       }
      }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new PrinterTask().execute("bar bar bar");
        new PrinterTask().execute("foo foo foo");

        System.out.println("onCreate() is done.");
    }
}

내가 기대하는 결과는 다음과 같습니다.

onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo

등등. 그러나 내가 얻는 것은 다음과 같습니다.

onCreate() is done.
bar bar bar
bar bar bar
bar bar bar

두 번째 AsyncTask는 실행되지 않습니다. execute () 문의 순서를 변경하면 foo 작업 만 출력을 생성합니다.

여기에 명백한 것이 누락되었거나 어리석은 일이 있습니까? 두 개의 AsyncTask를 동시에 실행할 수 없습니까?

편집 : 문제의 전화가 Android 1.5를 실행한다는 것을 깨달았습니다. 문제 설명을 업데이트했습니다. 따라서. Android 2.1을 실행하는 HTC Hero에는이 문제가 없습니다. 흠 …



답변

AsyncTask는 doInBackground ()에서 항목을 실행하기 위해 스레드 풀 패턴을 사용합니다. 이 문제는 초기에 (초기 Android OS 버전에서) 풀 크기가 1에 불과하여 많은 AsyncTask에 대한 병렬 계산이 없음을 의미합니다. 그러나 나중에 그들은 그 크기를 5로 고쳤으므로 최대 5 개의 AsyncTasks가 동시에 실행될 수 있습니다. 불행히도 나는 그들이 어떤 버전으로 정확하게 변경했는지 기억하지 못합니다.

최신 정보:

현재 (2012-01-27) API가 이에 대해 말한 내용은 다음과 같습니다.

처음 소개되었을 때 AsyncTasks는 단일 백그라운드 스레드에서 순차적으로 실행되었습니다. DONUT부터는 여러 작업을 병렬로 수행 할 수있는 스레드 풀로 변경되었습니다. HONEYCOMB 후에는 병렬 실행으로 인한 일반적인 응용 프로그램 오류를 피하기 위해이를 단일 스레드로 다시 변경할 계획입니다. 병렬 실행을 원한다면 THREAD_POOL_EXECUTOR와 함께이 메소드의 executeOnExecutor (Executor, Params …) 버전을 사용할 수 있습니다. 그러나 사용에 대한 경고는 주석을 참조하십시오.

DONUT는 Android 1.6이고 HONEYCOMB은 Android 3.0입니다.

업데이트 : 2

에 의해 코멘트보기 kabuko에서을 Mar 7 2012 at 1:27.

“여러 작업을 병렬로 실행할 수있는 스레드 풀”이 사용되는 API (1.6에서 시작하여 3.0으로 끝남)가 동시에 실행되는 AsyncTask의 수는 이미 실행을 위해 전달 된 작업 수에 따라 다릅니다. 그들의 완료되지 않은 doInBackground()아직.

이것은 2.2에서 나에 의해 테스트 / 확인되었습니다. 에 잠 들어있는 사용자 지정 AsyncTask가 있다고 가정합니다 doInBackground(). AsyncTask는 지연된 작업을 저장하기 위해 내부적으로 고정 크기 대기열을 사용합니다. 대기열 크기는 기본적으로 10입니다. 15 개의 사용자 지정 작업을 연속으로 시작하면 처음 5 개는에 입력 doInBackground()하지만 나머지는 대기열에서 비어있는 작업자 스레드를 기다립니다. 처음 5 개 중 하나가 완료되고 작업자 스레드를 해제하면 대기열의 작업이 실행을 시작합니다. 따라서이 경우 최대 5 개의 작업이 동시에 실행됩니다. 그러나 16 개의 사용자 지정 작업을 연속으로 시작하면 처음 5 개가로 들어가고 doInBackground()나머지 10 개가 대기열에 들어가지만 16 일 동안 새 작업자 스레드가 만들어져 즉시 실행을 시작합니다. 따라서이 경우 최대 6 개의 작업이 동시에 실행됩니다.

동시에 실행할 수있는 작업 수에는 제한이 있습니다. 이후 AsyncTask사용하는 작업자 스레드 (128) 및 당신이 충돌합니다 이상 138 사용자 정의 작업 응용 프로그램을 실행하려고하면 큐, 크기 10 고정했다 지연된 작업의 제한 최대 수의 스레드 풀 실행자 java.util.concurrent.RejectedExecutionException.

3.0부터 API는 AsyncTask.executeOnExecutor(Executor exec, Params... params)메소드 를 통해 사용자 정의 스레드 풀 실행기를 사용할 수 있습니다 . 예를 들어, 기본값 10이 필요한 경우 지연된 작업 큐의 크기를 구성 할 수 있습니다.

@Knossos가 언급했듯이 AsyncTaskCompat.executeParallel(task, params);지원 v.4 라이브러리에서 API 수준을 방해 하지 않고 작업을 병렬로 실행 하는 옵션이 있습니다 . 이 메소드는 API 레벨 26.0.0에서 더 이상 사용되지 않습니다.

업데이트 : 3

https://github.com/vitkhudenko/test_asynctask : 다음은 일련의 작업, 병렬 및 병렬 실행을 함께 수행하는 간단한 테스트 응용 프로그램입니다.

업데이트 : 4 (이 점을 지적한 @penkzhou에게 감사드립니다)

Android 4.4부터는 UPDATE : 2 섹션 AsyncTask에서 설명한 것과 다르게 작동 합니다. 너무 많은 스레드를 작성 하지 못하게 하는 수정 사항 이 있습니다 .AsyncTask

Android 4.4 (API 19) AsyncTask이전에는 다음 필드가있었습니다.

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

Android 4.4 (API 19)에서 위의 필드가 다음으로 변경되었습니다.

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

이 변경으로 큐 크기는 128 개 항목으로 증가하고 최대 스레드 수는 CPU 코어 수 * 2 + 1로 줄어 듭니다. 앱은 여전히 ​​동일한 수의 작업을 제출할 수 있습니다.


답변

이를 통해 API 4 이상 (Android 1.6 이상)을 사용하는 모든 Android 버전에서 병렬 실행이 가능합니다.

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}

Arhimed의 탁월한 답변을 요약 한 것입니다.

프로젝트 빌드 대상으로 API 레벨 11 이상을 사용하십시오. 이클립스에서 그것은입니다 Project > Properties > Android > Project Build Target. 더 낮은 API 수준과의 호환성 은 유지 하지 않습니다 . 이후에 소개 된 기능을 실수로 사용하면 Lint 오류가 발생하므로 걱정하지 마십시오 minSdkVersion. 이후에 소개 된 기능을 실제로 사용하려면minSdkVersion , 당신은 주석을 사용하여 이러한 오류를 억제 할 수 있지만,이 경우에, 당신은 호환성에 대해 돌볼 필요가 자신을 . 이것은 위의 코드 스 니펫에서 정확히 일어난 일입니다.


답변

@sulai 제안을보다 일반적인 것으로 만들기 :

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}   


답변

@sulai의 아주 좋은 요약에서 @Arhimed의 뽀얀 답변에 최신 업데이트 (UPDATE 4)를 포함 시키십시오.

void doTheTask(AsyncTask task) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above
        // Parallel AsyncTasks are possible, with the thread-pool size dependent on device
        // hardware
        task.execute(params);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to
        // Android 4.3
        // Parallel AsyncTasks are not possible unless using executeOnExecutor
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    } else { // Below Android 3.0
        // Parallel AsyncTasks are possible, with fixed thread-pool size
        task.execute(params);
    }
}


답변

비트 맵을로드하는 Android 개발자 예제는 사용자 정의 asynctask (젤리 빈에서 복사)를 효율적으로 사용하므로 <11보다 작은 apis에서 executeOnExecutor를 사용할 수 있습니다.

http://developer.android.com/training/displaying-bitmaps/index.html

코드를 다운로드하고 util 패키지로 이동하십시오.


답변

가능하다. 내 안드로이드 장치 버전은 4.0.4이고 android.os.Build.VERSION.SDK_INT는 15입니다

나는 3 스피너가

Spinner c_fruit=(Spinner) findViewById(R.id.fruits);
Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables);
Spinner c_beverage=(Spinner) findViewById(R.id.beverages);

또한 Async-Tack 클래스가 있습니다.

여기 내 스피너 로딩 코드가 있습니다.

RequestSend reqs_fruit = new RequestSend(this);
reqs_fruit.where="Get_fruit_List";
reqs_fruit.title="Loading fruit";
reqs_fruit.execute();

RequestSend reqs_vegetable = new RequestSend(this);
reqs_vegetable.where="Get_vegetable_List";
reqs_vegetable.title="Loading vegetable";
reqs_vegetable.execute();

RequestSend reqs_beverage = new RequestSend(this);
reqs_beverage.where="Get_beverage_List";
reqs_beverage.title="Loading beverage";
reqs_beverage.execute();

이것은 완벽하게 작동합니다. 내 스피너가 하나씩로드되었습니다. 나는 executeOnExecutor를 사용하지 않았다.

여기 내 비동기 작업 클래스가 있습니다.

public class RequestSend  extends AsyncTask<String, String, String > {

    private ProgressDialog dialog = null;
    public Spinner spin;
    public String where;
    public String title;
    Context con;
    Activity activity;
    String[] items;

    public RequestSend(Context activityContext) {
        con = activityContext;
        dialog = new ProgressDialog(activityContext);
        this.activity = activityContext;
    }

    @Override
    protected void onPostExecute(String result) {
        try {
            ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items);
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spin.setAdapter(adapter);
        } catch (NullPointerException e) {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        } catch (Exception e)  {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
        super.onPostExecute(result);

        if (dialog != null)
            dialog.dismiss();
    }

    protected void onPreExecute() {
        super.onPreExecute();
        dialog.setTitle(title);
        dialog.setMessage("Wait...");
        dialog.setCancelable(false);
        dialog.show();
    }

    @Override
    protected String doInBackground(String... Strings) {
        try {
            Send_Request();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }

    public void Send_Request() throws JSONException {

        try {
            String DataSendingTo = "http://www.example.com/AppRequest/" + where;
            //HttpClient
            HttpClient httpClient = new DefaultHttpClient();
            //Post header
            HttpPost httpPost = new HttpPost(DataSendingTo);
            //Adding data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);

            nameValuePairs.add(new BasicNameValuePair("authorized","001"));

            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            // execute HTTP post request
            HttpResponse response = httpClient.execute(httpPost);

            BufferedReader reader;
            try {
                reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuilder builder = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    builder.append(line) ;
                }

                JSONTokener tokener = new JSONTokener(builder.toString());
                JSONArray finalResult = new JSONArray(tokener);
                items = new String[finalResult.length()];
                // looping through All details and store in public String array
                for(int i = 0; i < finalResult.length(); i++) {
                    JSONObject c = finalResult.getJSONObject(i);
                    items[i]=c.getString("data_name");
                }

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


답변

작업을 병렬로 실행하려면 executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name")Android 버전 3.0 이후 에 메소드를 호출해야합니다 . 그러나이 메소드는 자체적으로 병렬로 실행되기 때문에 Android 3.0 이전 및 1.6 이후에는 존재하지 않으므로 다른 Android 버전에서 예외를 발생시키지 않도록 프로젝트에서 자체 AsyncTask 클래스를 사용자 정의하는 것이 좋습니다.