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

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



답변

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비워 둘 수 없습니다 .


답변

이 답변 : 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);


답변

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

방법 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를 실행할 수 없습니다 : 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와 같은 다중 스레딩에서 올 수있는 모든 문제를 피하기 위해 문서에 설명되어 있습니다.


답변

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

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

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

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

데이비드


답변

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


답변

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