Android SDK AsyncTask doInBackground 未运行(子类)

Posted

技术标签:

【中文标题】Android SDK AsyncTask doInBackground 未运行(子类)【英文标题】:Android SDK AsyncTask doInBackground not running (subclass) 【发布时间】:2012-02-25 12:55:06 【问题描述】:

截至 2012 年 2 月 15 日,我还没有找到一个很好的解释,也没有找到为什么这不起作用的原因。最接近解决方案的是使用传统的Thread 方法,但是为什么要包含一个在 Android SDK 中(似乎)不起作用的类?

晚安!

我有一个 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() 由接口 ParseListener 的回调调用。但是,由于我什至什么都不做,除了 log.v 在 doInBackground() 中,我首先发现这甚至没有必要提出。

编辑 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);

【问题讨论】:

活动是否可能在任务完成之前完成? 极不可能。在那种情况下,我的其他线程将无法正常运行?而且我现在只有一项活动。 我的应用程序有同样的问题 - doInBackground 要么没有被调用,要么被调用了很长的延迟。这是我有限的观察:完全相同的代码在 android 2.3.3 智能手机和 Android 2.3.3 模拟器上完美运行,但在 Android 4.0.3 平板电脑和一堆 Android 4.x.x 模拟器上存在这个问题。很容易得出结论,这个问题是在较新版本的 Android 中引入的。 对不起,但我忘了提到这个问题只发生在 Activity 的第二个 AsyncTask 第一个 AsyncTask 总是工作正常。 Hong,你试过马修的回答吗?我大部分时间都在使用 Android 游戏 ATM 并且有一段时间没有使用它,所以我无法判断他的答案是否真的有效。如果它不适合你,那么我接受他的回答可能很糟糕...... 【参考方案1】:

您应该查看此答案:https://***.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);

【讨论】:

我在回顾这篇文章时一直很糟糕;我早就离开了这个项目。我会接受这个作为答案,因为人们似乎说它有效。 这对我有用,但我希望我明白为什么。它在执行之前运行良好,然后它停止了。我正在做的一件事是在同一个异步任务的 onPostExecute 中启动一个新的异步任务(即我递归调用它)也许这与问题有关? 我认为这应该给你所有你需要的解释:commonsware.com/blog/2012/04/20/… @Matthieu : 先生,我真的非常感谢你!!!几个小时以来,我一直在努力解决这个问题,而您的解决方案使一切都像魅力一样工作!非常感谢您的精彩回答。我希望我能投不止一个赞成票! @joao2fast4u web.archive.org/web/20131219080911/http://www.jayway.com/2012/…【参考方案2】:

Matthieu 的解决方案适用于大多数人,但有些人可能会遇到问题;除非挖掘此处提供或来自网络的许多链接,例如Anders Göransson 的解释。 如果 executeOnExecutor 仍在单线程中工作,我正在尝试总结其他一些阅读并快速解释解决方案...

AsyncTask().execute(); 的行为在 Android 版本中有所改变。在 Donut (Android:1.6 API:4) 任务被串行执行之前,从 DonutGingerbread (Android:2.3 API:9) 任务并行执行;由于 Honeycomb (Android:3.0 API:11) 执行已切换回顺序;但是,为并行执行添加了一个新方法 AsyncTask().executeOnExecutor(Executor)

在顺序处理中,所有异步任务都在单个线程中运行,因此必须在前一个任务结束之前等待。如果您需要立即执行代码,则需要在单独的线程中并行处理任务。

Donut 和 Honeycomb 版本之间不支持 AsyncTask 串行执行,而在 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(按顺序运行任务在蜂窝后)。 如果您尚未定义targetSdkVersion,则minSdkVersion 将自动被视为targetSdkVersion。 因此,要在后 Honeycomb 上并行运行 AsyncTask,您不能将 targetSdkVersion 留空。

【讨论】:

很好的答案。虽然 Matthieu 没有错,但我接受了这一点,因为您添加了一堆重要信息。 @Nashe 非常感谢。这真的很有帮助。我与同样的问题斗争了 3 天。再次感谢:) 拯救了我的一天!希望这个答案更容易找到。 嘿@Nashe,我的问题有点尴尬。在今天之前,我在 AsyncTask 上使用 .execute() 方法,并且代码运行良好。但是今天我遇到了问题 - 控件没有进入 doInBackground() 方法。尽管您提供的解决方案有效,但我很困惑以前没有解决方案它是如何工作的。我以前和现在都使用同一组设备。 为什么会这样?为什么它不能按预期工作? :(【参考方案3】:

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

方式 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 进行更改:( @vinu,我建议你使用常用的异步任务和常用的方法来执行AsyncTask。希望这会对你有所帮助。 嘿,这对我帮助很大!谢谢!【参考方案4】:

我遇到了同样的问题:在我对第一个 AsyncTask 调用“execute”之后,不能再执行第二个 AsyncTask:doInBackground 只为第一个调用。

要回答为什么会发生这种情况,请查看answer(不同的行为取决于 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);

对于您的更新问题:docs 中对此进行了解释 基本上只是为了避免可能来自多线程的所有问题,比如相互引用......

【讨论】:

【参考方案5】:

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

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

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

希望这是有道理的。如果我能提供更多帮助,请告诉我。

大卫

【讨论】:

在你的答案中添加这个帖子有一个有趣的答案***.com/questions/4080808/…。 感谢您的精彩回答!我提高了这一点,因为我认为这可能是一个常见的 AsyncTask 初学者问题。唉,这不是这个问题的正确答案。这两个类都在主 UI 线程上运行的活动的 onCreate() 中实例化。我在这个项目中只有一项活动。 @manjusg 我一直认为它与 AsyncTask 不稳定有关,当同时运行多个时可能更是如此。如果有,为什么? 我真的不知道 SO 有什么政策可以连续 3 次快速发布,但我在另一个线程中发现了这个...foo.jasonhudgins.com/2010/05/limitations-of-asynctask.html"AsyncTask 使用静态内部工作队列10 个元素的硬编码限制。”这可能证明了一些事情,但我只有两个 AsyncTask 子类的实例!我真的很想避免使用普通的线程方法,因为最终会在 dere 中完成大量解析。【参考方案6】:

Android 是残酷的!我无法相信这一点,从今天到今天发生了多么糟糕的实现。一天是一个线程,下一个是 5,另一个是 128。

无论如何,这里的 AsyncTask 替代品几乎下降了。如果您愿意,您甚至可以将其称为 AsyncTask,但为避免混淆,将其称为 ThreadedAsyncTask。您需要调用 executeStart() 而不是 execute,因为 execute() 是最终的。

/**
 * @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 将异步操作限制为一个线程,是吗?那将是非常愚蠢的。 (我已经离开 Android 游戏一段时间了。:)) 是的,在 Android 3.0+ 上,如果您不使用 AsyncTask.THREAD_POOL_EXECUTOR,您只会获得一个线程池。自己尝试一下,两个 AsyncTask,然后睡在一个 doInBackground 中。来自 Android AsyncTask 文档:“从 HONEYCOMB 开始,任务在单个线程上执行,以避免并行执行导致的常见应用程序错误。”【参考方案7】:

我知道这对于线程来说可能真的很晚了,但是它不能在以后的 android 模拟器上工作是有原因的。当 asynctask 被引入时,android 只允许你一次运行一个,然后一段时间后,我不确定是哪个版本,他们允许你一次运行多个 asynctask,这导致了很多应用程序的问题,所以在 Honeycomb+ 他们恢复为只允许一次运行一个异步任务。除非你手动更改线程池。 希望能为人们解决一两件事。

【讨论】:

【参考方案8】:

我认为它是 sdk。我遇到了同样的问题,将目标 sdk 从 15 更改为 11 后,一切正常。

使用 sdk15,即使 AsyncTask.Status 为 RUNNING,doInBackground 也不会被调用。我确实认为这与 ui 线程有关。

【讨论】:

我既不能否认也不能确认,因为我现在真的没有时间测试它。我只能说我使用的是 SDK 15,所以很有可能。【参考方案9】:

根据 Matthieu 的回答,在 helper 类下方根据 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);

【讨论】:

以上是关于Android SDK AsyncTask doInBackground 未运行(子类)的主要内容,如果未能解决你的问题,请参考以下文章

Android SDK AsyncTask doInBackground 未运行(子类)

android中 如果要你来设计AsyncTask,你怎么设计

Android AsyncTask问题

Android 对线程封装了:AsyncTask, HandlerThread和线程池。 有知道这三个如何选择吗?

android中asynctask和thread的区别

Android面试Android异步任务AsyncTask