Android SDK AsyncTask doInBackground未运行(子类)

Ser*_*ruK 90 multithreading android android-emulator android-asynctask

截至2012年2月15日,我还没有找到一个很好的解释,也不知道为什么这不起作用.最接近解决方案的是使用传统的Thread方法,但为什么要包含一个在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
Run Code Online (Sandbox Code Playgroud)

这是这样执行的:

xmlAsync xmlThread = new xmlAsync();

xmlThread.execute("http://www.nothing.com");
Run Code Online (Sandbox Code Playgroud)

现在这个子类遇到了一点错误.以前它做了一些xml-parsing,但是当我注意到它的doInBackground()没有被调用时,我逐行删除它,最后以这样结束:

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

由于某种原因,没有记录任何内容.但是,我补充说:

@Override
protected void onPreExecute() 
{
        Log.v(TAG, "onPreExecute");
        super.onPreExecute();
}
Run Code Online (Sandbox Code Playgroud)

并且在执行线程时确实记录了该行.所以不知何故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);
    }
Run Code Online (Sandbox Code Playgroud)

_tableManager.addRSSItem()或多或少地向SQLiteDatabase添加一行,并使用activity的上下文进行初始化.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();
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑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);
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*ieu 159

你应该检查这个答案:https://stackoverflow.com/a/10406894/347565以及它包含的谷歌组的链接.

我遇到了类似的问题,仍然不清楚为什么它不起作用,但我改变了我的代码并且问题消失了:

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);
Run Code Online (Sandbox Code Playgroud)

  • @joao2fast4u http://web.archive.org/web/20131219080911/http://www.jayway.com/2012/11/28/is-androids-asynctask-executing-tasks-serially-or-concurrently (3认同)

Nas*_*she 107

Matthieu的解决方案适用于大多数人,但有些人可能会面临问题; 除非在这里或网上提供许多链接,比如AndersGö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之后的并行处理:检查Build版本并基于该使用.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();
Run Code Online (Sandbox Code Playgroud)

NOTE:函数.executeOnExecutor()检查targetSdkVersion项目是否小于或等于HONEYCOMB_MR1(Android:2.1 API:7)然后强制执行程序THREAD_POOL_EXECUTOR(在后蜂窝中顺序运行任务).
如果你还没有定义一个targetSdkVersionminSdkVersion自动被认为是targetSdkVersion.
因此,为了在后蜂窝上并行运行AsyncTask,你不能targetSdkVersion留空.

  • 嘿@Nashe,我的问题有点尴尬.在今天之前,我在AsyncTask上使用.execute()方法,代码完全正常.但今天我遇到了问题 - 控件没有进入doInBackground()方法.虽然你提供的解决方案正在发挥作用,但我很困惑,如果没有解决方案,它的工作方式如何.我之前和现在使用的是同一套设备. (4认同)

Hir*_*tel 8

你可以通过两种方式做到这一点:

方式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();
  }
Run Code Online (Sandbox Code Playgroud)

如果方式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);
Run Code Online (Sandbox Code Playgroud)

希望这会帮助你.

  • 嘿,这对我有很大帮助!谢谢! (2认同)

小智 6

我遇到了同样的问题:在第一个调用"execute"之后无法执行第二个AsyncTask:doInBackground只调用第一个.

要回答为什么会发生这种情况,请检查此答案(根据SDK的不同行为)

但是,对于您的情况,使用executeOnExecutor可以避免这个障碍(从3.0开始可用,使用4.0.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.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR
 ,"http://www.nothing.com", null);
}
Run Code Online (Sandbox Code Playgroud)

对于您的更新问题:它在文档中进行了解释 基本上只是为了避免可能来自多线程的所有问题,如干扰....


小智 5

我想知道的一件事,它可能实际上解决了你的问题,你在哪里实例化你的类的实例并调用execute()方法?如果您阅读AsyncTask的文档,则这两个操作都需要在主UI线程上进行.如果你正在创建你的对象并从其他线程调用execute,那么onPreExecute可能会触发,我不是100%肯定在这里,但后台线程将不会被创建和执行.

如果要从后台线程创建AsyncTask实例,或者在主UI线程上没有进行其他操作,可以考虑使用以下方法: Activity.runOnUiThread(Runnable)

您需要访问正在运行的Activity的实例来调用该方法,但它将允许您从UI线程上未运行的其他代码运行UI线程上的代码.

希望有道理.如果我能提供更多帮助,请告诉我.

大卫