Android SDK AsyncTask doInBackground가 실행되지 않음 (하위 클래스)


90

2012 년 2 월 15 일 현재 나는 이것이 작동하지 않는 이유에 대한 좋은 설명이나 이유를 아직 찾지 못했습니다. 솔루션에 가장 가까운 방법은 기존의 스레드 접근 방식 을 사용하는 것이지만 Android SDK에서 작동하지 않는 클래스를 포함하는 이유는 무엇입니까?

Evenin 'SO!

AsyncTask 하위 클래스가 있습니다.

// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener

다음과 같이 실행됩니다.

xmlAsync xmlThread = new xmlAsync();

xmlThread.execute("http://www.nothing.com");

이제이 하위 클래스에 약간의 오류가 발생했습니다. 이전에는 xml 구문 분석을 수행했지만 doInBackground () 가 호출되지 않은 것을 알았을 때 한 줄씩 제거하고 마침내 다음과 같이 끝납니다.

@Override
protected Void doInBackground(String... params) 
{
    Log.v(TAG, "doInBackground");
        return null;
}

어떤 이유로 든 아무것도 기록하지 않았습니다. 그러나 나는 이것을 추가했다.

@Override
protected void onPreExecute() 
{
        Log.v(TAG, "onPreExecute");
        super.onPreExecute();
}

그리고 그 줄은 실제로 스레드를 실행할 때 기록됩니다. 그래서 어떻게 든 onPreExecute ()가 호출되지만 doInBackground ()는 아닙니다 . 나는 다른 AsyncTask가 백그라운드에서 동시에 실행되어 잘 작동합니다.

저는 현재 북극에 가까운 에뮬레이터 SDK 버전 15, Eclipse, Mac OS X 10.7.2에서 앱을 실행하고 있습니다.

편집하다:

@Override
    protected void onProgressUpdate(RSSItem... values) {

        if(values[0] == null)
        {
                            // activity function which merely creates a dialog
            showInputError();
        }
        else
        {

            Log.v(TAG, "adding "+values[0].toString());
            _tableManager.addRSSItem(values[0]);
        }


        super.onProgressUpdate(values);
    }

_tableManager.addRSSItem () 다소간은 활동의 컨텍스트로 초기화 된 SQLiteDatabase에 행을 추가합니다. publishProgress ()는 Interface ParseListener의 콜백에 의해 호출됩니다. 그러나 doInBackground ()에서 log.v 외에는 아무것도하지 않았기 때문에 처음에는 이것이 불필요하다는 것을 알았습니다.

편집 2 :

자, 완벽하게 명확하게하기 위해 이것은 동일한 활동에서 실행되고 완벽하게 잘 작동하는 다른 AsyncTask입니다.

private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
    Integer prevCount;
    boolean run;

    @Override
    protected void onPreExecute() {
        run = true;
        super.onPreExecute();
    }

    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        run = true;
        prevCount = 0;

        while(run)
        {
            ArrayList<RSSItem> items = _tableManager.getAllItems();

            if(items != null)
            {
                if(items.size() > prevCount)
                {
                    Log.v("db Thread", "Found new item(s)!");
                    prevCount = items.size();

                    RSSItem[] itemsArray = new RSSItem[items.size()];

                    publishProgress(items.toArray(itemsArray));
                }
            }               

            SystemClock.sleep(5000);
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(RSSItem... values) {

        ArrayList<RSSItem> list = new ArrayList<RSSItem>();

        for(int i = 0; i < values.length; i++)
        {
            list.add(i, values[i]);
        }

        setItemsAndUpdateList(list);

        super.onProgressUpdate(values);
    }

    @Override
    protected void onCancelled() {
        run = false;

        super.onCancelled();
    }
}

편집 3 :

한숨, 미안 해요 질문을 못해요 그러나 여기에 태스크의 초기화가 있습니다.

xmlAsync _xmlParseThread;
dbAsync _dbLookup;

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

_dbLookup = new dbAsync();
_dbLookup.execute();

_xmlParseThread = new xmlAsync();       
_xmlParseThread.execute("http://www.nothing.com", null);
}

작업이 완료되기 전에 활동이 완료 될 수 있습니까?
Paul Nikonowicz 2012

가능성이 거의 없습니다. 이 경우 내 다른 스레드가 제대로 실행되지 않을까요? 그리고 지금은 활동이 하나뿐입니다.
SeruK 2012

2
내 앱에 동일한 문제가 있습니다. doInBackground가 호출되지 않거나 매우 긴 지연으로 호출됩니다. 내 제한적인 관찰은 다음과 같습니다. 정확히 동일한 코드가 Android 2.3.3 스마트 폰 및 Android 2.3.3 에뮬레이터에서 완벽하게 작동하지만 Android 4.0.3 태블릿 및 여러 Android 4.xx 에뮬레이터에서는이 문제가 발생합니다. 이 문제가 최신 버전의 Android에서 도입되었다고 결론 내리는 것은 매우 유혹적입니다.
Hong

죄송합니다.이 문제는 활동의 두 번째 AsyncTask에서만 발생한다는 것을 잊었습니다. 첫 번째 AsyncTask는 항상 잘 작동합니다.
Hong

홍, 마티유의 대답을 해보 셨나요? 나는 대부분 안드로이드 게임 ATM을 사용하지 않고 한동안 작업하지 않았기 때문에 그의 답변이 실제로 작동하는지 알 수 없습니다. 당신을 위해하지 않는 경우, 어쩌면 나를 나쁜보다 ... 그의 대답을 적용합니다
SeruK

답변:


107

Matthieu의 솔루션은 대부분의 경우 잘 작동하지만 일부는 문제에 직면 할 수 있습니다. 여기에 제공된 많은 링크 또는 Anders Göransson 의 설명 과 같이 웹에서 파헤쳐지지 않는 한 . 바로 여기에 다른 읽기를 요약하고 executeOnExecutor가 단일 스레드에서 계속 작동하는 경우 솔루션을 빠르게 설명하려고합니다.

의 동작이 AsyncTask().execute();Android 버전을 통해 변경되었습니다. 전에 도넛 (안드로이드 1.6 API : 4) 작업에서 연속적으로 실행 된 도넛진저 브레드 (안드로이드 2.3 API : 9) 작업을 병렬로 실행; Honeycomb (Android : 3.0 API : 11) 실행이 다시 순차적으로 전환 되었기 때문에 ; AsyncTask().executeOnExecutor(Executor)그러나 병렬 실행을 위해 새로운 방법 이 추가되었습니다.

순차 처리에서 모든 비동기 작업은 단일 스레드에서 실행되므로 이전 작업이 종료되기 전에 기다려야합니다. 코드를 즉시 실행해야하는 경우 별도의 스레드에서 병렬로 처리 할 작업이 필요합니다.

AsyncTask를 사용하면 Donut과 Honeycomb 버전간에 직렬 실행을 사용할 수 없지만 Donut 이전에는 병렬 실행을 사용할 수 없습니다.

Donut 이후 병렬 처리 : 빌드 버전을 확인하고이를 기반으로 .execute () 또는 .executeOnExecutor () 메서드를 사용합니다. 다음 코드가 도움이 될 수 있습니다 ...

AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask code goes here
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
    myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
    myTask.execute();

NOTE:함수 .executeOnExecutor()targetSdkVersion프로젝트가 HONEYCOMB_MR1(Android : 2.1 API : 7) 보다 작거나 같은지 확인한 다음 실행기를 강제합니다 THREAD_POOL_EXECUTOR(Honeycomb 이후 작업을 순차적으로 실행).
당신이 정의하지 않은 경우 targetSdkVersion다음 minSdkVersion자동으로 간주됩니다 targetSdkVersion.
따라서 Honeycomb 이후에 AsyncTask를 병렬로 실행하려면 targetSdkVersion비워 둘 수 없습니다 .


1
아주 좋은 대답입니다. Matthieu가 틀린 것은 아니지만 중요한 정보를 많이 추가했기 때문에 이것을 수락합니다.
SeruK 2014

@ Nashe 정말 감사합니다. 정말 도움이됩니다. 나는 3 일 동안 같은 문제로 싸우고 있었다. 다시 한 번 감사드립니다 :)

내 하루를 구했습니다! 이 답변이 더 쉽게 찾을 수 있기를 바랍니다.
zjk

4
안녕하세요 @ Nashe, 내 문제는 조금 어색합니다. 오늘 전에는 AsyncTask에서 .execute () 메서드를 사용했고 코드가 완벽하게 작동했습니다. 하지만 오늘 문제가 생겼습니다. 컨트롤이 doInBackground () 메서드에 들어 가지 않습니다. 제공하는 솔루션이 작동하지만 솔루션 없이는 이전에 어떻게 작동했는지 의아해합니다. 이전과 지금 동일한 장치 세트를 사용하고 있습니다.
Ravi Sisodia 2014 년

왜 이렇게해야합니까? 예상대로 작동하지 않는 이유는 무엇입니까? :(
Nikolay R

160

이 답변 : https://stackoverflow.com/a/10406894/347565 및 포함 된 Google 그룹에 대한 링크를 확인해야합니다.

나는 당신과 비슷한 문제가 있었지만 왜 작동하지 않는지 명확하지 않지만 다음과 같이 코드를 변경하고 문제가 사라졌습니다.

ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() { ... };
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
else
    my_task.execute((Void[])null);

나는이 포스트를 되돌아 보는 것이 매우 나빴다. 나는 오랫동안 프로젝트에서 멀어졌습니다. 사람들이 그것이 효과가 있다고 말하는 것처럼 보이기 때문에 나는 이것을 대답으로 받아 들일 것입니다.
SeruK

이것은 방금 나를 위해 일했지만 그 이유를 이해했으면 좋겠습니다. 그 전에 실행으로 잘 작동하고 중지되었습니다. 내가하고있는 한 가지는 동일한 asynctask의 onPostExecute 내부에서 새로운 asynctask를 시작하는 것입니다 (즉, 재귀 적으로 호출하고 있습니다) 아마도 문제와 관련이 있습니까?
steveh 2013

나는 이것이 당신에게 필요한 모든 설명을 제공 할 것이라고 생각한다 : commonsware.com/blog/2012/04/20/…
Matthieu

1
@Matthieu : 선생님, 정말 감사합니다! 나는 몇 시간 동안이 문제에 대해 머리를 치고 있었고 당신의 해결책은 모든 것이 매력처럼 작동하도록 만들었습니다! 환상적인 답변에 감사드립니다. 하나 이상의 찬성표를 줄 수 있으면 좋겠어요 !!
Swayam


9

다음 두 가지 방법으로이 작업을 수행 할 수 있습니다.

방법 1 :

if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13
  {
      asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
  }
else // Below Api Level 13
  {
      asyncTask.execute();
  }

방법 1 이 작동하지 않는 경우 방법 2 를 시도하십시오 .

방법 2 :

int mCorePoolSize = 60;
int mMaximumPoolSize = 80;
int mKeepAliveTime = 10;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize);
Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue);
asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);

이것이 당신을 도울 것입니다.


슈퍼 친구는 작동하지만 AsyncTask.THREAD_POOL_EXECUTOR를 사용하는 다음 후속 비동기 작업이 실패하므로 프로젝트 전체에서 CustomExecutor로 변경해야합니다. (
kumar

@vinu, 나는 AsyncTask를 실행하기 위해 일반적인 비동기 작업과 일반적인 방법을 사용하는 것이 좋습니다. 이것이 당신을 도울 것입니다.
Hiren Patel

2
이봐, 이것은 나를 많이 도왔다! 감사!
Justin Ebby

6

나는 같은 문제가 있었다 : 내가 첫 번째 "실행"을 호출 한 후 두 번째 AsyncTask를 실행할 수 없습니다 : doInBackground는 첫 번째에만 호출됩니다.

왜 이런 일이 발생하는지 대답 하려면이 대답을 확인하십시오 (SDK에 따라 다른 동작).

그러나 귀하의 경우이 장애물은 executeOnExecutor를 사용하여 피할 수 있지만 (4.0.3을 사용하여 3.0부터 사용 가능) 스레드 풀 크기 및 대기열 제한에 유의하십시오.

다음과 같이 시도해 볼 수 있습니까?

xmlAsync _xmlParseThread;
dbAsync _dbLookup;

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

_dbLookup = new dbAsync();
_dbLookup.execute();

_xmlParseThread = new xmlAsync();       
_xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
 ,"http://www.nothing.com", null);
}

업데이트 질문에 대해 : 기본적으로 intereference와 같은 다중 스레딩에서 올 수있는 모든 문제를 피하기 위해 문서에 설명되어 있습니다.


5

내가 알고 싶은 한 가지는 실제로 문제를 해결할 수 있습니다. 클래스의 인스턴스를 인스턴스화하고 execute () 메서드를 호출하는 것입니다. AsyncTask에 대한 문서를 읽으면 두 작업 모두 기본 UI 스레드에서 수행되어야합니다. 객체를 생성하고 다른 스레드에서 execute를 호출하는 경우 onPreExecute가 실행될 수 있습니다. 여기서는 100 % 확실하지 않지만 백그라운드 스레드는 생성 및 실행되지 않습니다.

백그라운드 스레드에서 AsyncTask의 인스턴스를 만들거나 기본 UI 스레드에서 발생하지 않는 다른 작업을 만드는 경우 다음 메서드를 사용할 수 있습니다. Activity.runOnUiThread (Runnable)

해당 메서드를 호출하려면 실행중인 Activity의 인스턴스에 액세스해야하지만 UI 스레드에서 실행되지 않는 다른 코드의 UI 스레드에서 코드를 실행할 수 있습니다.

이해가 되길 바랍니다. 도움이 더 필요하면 알려주세요.

데이비드


귀하의 답변에 추가이 스레드에는 흥미로운 답변이 있습니다. stackoverflow.com/questions/4080808/… .
manjusg 2012

훌륭한 답변에 감사드립니다! 나는 이것이 일반적인 AsyncTask- 초보자 문제라고 생각하기 때문에 이것을 올렸습니다. 아아,이 문제에 대한 정답이 아닙니다. 두 클래스 모두 기본 UI 스레드에서 실행되는 활동의 onCreate ()에서 인스턴스화됩니다. 이 프로젝트에는 활동이 하나뿐입니다.
SeruK 2012

@manjusg 나는 AsyncTask가 불안정한 것과 관련이 있다고 생각했습니다. 그렇다면 그 이유는 무엇입니까?
SeruK 2012

세 번 연속으로 빠르게 게시하는 것과 관련하여 어떤 정책이 있는지는 잘 모르겠지만 다른 스레드에서 이것을 발견했습니다 ... foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html "AsyncTask는 하드 코딩 된 10 개 요소 제한이있는 정적 내부 작업 대기열. " 이것은 뭔가를 증명할 수 있지만 AsyncTask-subclasses의 두 인스턴스가 있습니다! 결국에는 많은 파싱이 끝날 것이기 때문에 정상적인 스레딩 방법을 사용하는 것을 정말로 피하고 싶습니다.
SeruK 2012

2

Android는 잔인합니다! 나는 이것을 믿을 수 없다. 날마다 변화하는 잘못된 구현이다. 하루는 단일 스레드이고 다음은 5이고 다른 스레드는 128입니다.

어쨌든 여기에 주식 AsyncTask를 대체하는 거의 하락이 있습니다. 원하는 경우 AsyncTask라고 부를 수도 있지만 혼동을 피하기 위해 ThreadedAsyncTask라고합니다. execute ()가 최종이므로 execute 대신 executeStart ()를 호출해야합니다.

/**
 * @author Kevin Kowalewski
 *
 */
public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { 
    public AsyncTask<Params, Progress, Result> executeStart(Params... params){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
            return executePostHoneycomb(params);
        }else{
            return super.execute(params);
        }
    }


    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params){
        return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); 
    }
}

잠깐, Android의 일부 버전이 비동기 작업을 하나의 스레드로 제한한다고 말하는 것이 아닙니다. 그것은 엄청나게 어리석은 일입니다. (나는 잠시 동안 안드로이드 게임 밖으로 있었어요 :).)
SeruK

예, Android 3.0 이상에서 AsyncTask.THREAD_POOL_EXECUTOR를 사용하지 않으면 스레드 풀이 하나만 제공됩니다. 자신을 위해 두 개의 AsyncTask를 시도하고 하나의 doInBackground에서 잠을 자십시오. Android AsyncTask 문서에서 : "HONEYCOMB부터 작업은 병렬 실행으로 인한 일반적인 애플리케이션 오류를 방지하기 위해 단일 스레드에서 실행됩니다."
Kevin Parker

1

나는 이것이 스레드에 대해 정말 늦을 수 있다는 것을 알고 있지만 나중에 안드로이드 에뮬레이터에서 작동하지 않는 이유가 있습니다. asynctask가 소개되었을 때 android는 한 번에 하나씩 만 실행할 수있게했고, 나중에 어떤 버전인지 잘 모르겠습니다. 한 번에 여러 개의 비동기 작업을 실행할 수 있었으며 이로 인해 많은 앱에서 문제가 발생했으며 Honeycomb +에서는 다음으로 만 되돌아갔습니다. 한 번에 하나의 비동기 작업을 실행할 수 있습니다. 스레드 풀을 수동으로 변경하지 않는 한. 사람들을 위해 한두 가지를 정리하기를 바랍니다.


0

나는 그것의 sdk를 생각한다. 나는 같은 문제가 있었고 대상 SDK를 15에서 11로 변경 한 후 모든 것이 완벽하게 작동합니다.

sdk15를 사용하면 AsyncTask.Status가 RUNNING이지만 doInBackground가 호출되지 않습니다. 나는 그것이 ui 스레드와 관련이 있다고 생각합니다.


지금 당장 테스트 할 시간이 없기 때문에 부정하거나 확인할 수 없습니다. 제가 말할 수있는 것은 제가 SDK 15를 사용하고 있었다는 것이므로 가능성이 매우 높습니다.
SeruK 2012

0

Matthieu의 답변에 따라 애플리케이션에서 코드 중복을 방지하기 위해 SDK 버전에 따라 올바르게 실행 하는 도우미 클래스 아래 AsyncTask:

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.os.Build;

public class AsyncTaskExecutor<Params, Progress, Result> {

  @SuppressLint("NewApi")
  public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
      return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    }  else{
      return asyncTask.execute(params);
    }
  }

}

사용 예 :

public class MyTask extends AsyncTask<Void, Void, List<String>> {

...

final MyTask myTask = new MyTask();
new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.