Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 任务一直在等待?_Java_Android_Android Asynctask - Fatal编程技术网

Java 任务一直在等待?

Java 任务一直在等待?,java,android,android-asynctask,Java,Android,Android Asynctask,我的一个活动中的按钮调用AsyncTask,该任务更新ListView的SimpleCursorAdapter的基础游标。每次单击该按钮时,都会为异步任务添加一个新线程,任务完成(进入“等待”状态)。如果我单击按钮5次或更多次,5个异步任务将以“等待”状态结束。这是正常的还是我有内存泄漏 异步任务 private class updateAdapter extends AsyncTask<Void, Void, Void> { @Override protected

我的一个活动中的按钮调用AsyncTask,该任务更新ListView的SimpleCursorAdapter的基础游标。每次单击该按钮时,都会为异步任务添加一个新线程,任务完成(进入“等待”状态)。如果我单击按钮5次或更多次,5个异步任务将以“等待”状态结束。这是正常的还是我有内存泄漏

异步任务

private class updateAdapter extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        // Open database connection
        if(_db == null || !_db.isOpen()) _db = new DatabaseWrapper(ActivityShowWOD.this).getWritableDatabase();
        Cursor WODcursor;

        // Check if a wod_id is set
        if(_wod_id == -1) {
            // Grab filters from preferences and at the same time build SQLselection string
            SharedPreferences prefs = getSharedPreferences("Preferences", 0);
            String[] filterNames = getResources().getStringArray(R.array.filters_values);
            boolean[] filterValues = new boolean[filterNames.length];
            String SQLselection = "";

            for (int i = 0; i < filterNames.length; i++) {
                filterValues[i] = prefs.getBoolean(filterNames[i], false);

                // Build SQL query
                if(filterValues[i] == true) {
                    SQLselection += filterNames[i] + " = 1 OR " +  filterNames[i] + " = 0";
                } else {
                    SQLselection += filterNames[i] + " = 0";
                }

                // Add an "AND" if there are more filters 
                if(i < filterNames.length - 1) SQLselection += " AND ";
            }

            // Get all WODs matching filter preferences 
            WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, 
                                      new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME,
                                                     DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, 
                                      SQLselection, null, null, null, null);

            // Move the Cursor to a random position
            Random rand = new Random();
            WODcursor.moveToPosition(rand.nextInt(WODcursor.getCount()));

            // Store wod_id
            _wod_id = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_ID));
        } else {
            // Get the cursor from the wod_id
            WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, 
                                 new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME,
                                                DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, 
                                 DatabaseConstants.WORKOUTS_ID + " = " + _wod_id, null, null, null, null);

            WODcursor.moveToFirst();
        }

        // Store WOD information into class instance variables and close cursor
        _wod_cfid = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_CFID));
        _wod_name = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NAME));
        _wod_notes = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NOTES));
        WODcursor.close();

        // Return all exercises pertaining to this WOD
        _excCursor = _db.query(DatabaseConstants.TBL_EXERCISES, 
                              new String[] { DatabaseConstants.EXERCISES_ID, DatabaseConstants.EXERCISES_EXERCISE,
                                             DatabaseConstants.EXERCISES_REPS, DatabaseConstants.EXERCISES_NOTES }, 
                              DatabaseConstants.EXERCISES_WOD_ID + " = " + _wod_id, null, null, null, 
                              DatabaseConstants.EXERCISES_ID + " ASC");
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        _adapter.changeCursor(_excCursor);
        _adapter.notifyDataSetChanged();
        _WODlist.setOnItemClickListener(new WODlistClickListener());
    }

}
在单击Listener的按钮中:

            // Reset wod_id
            _wod_id = -1;

            // Update the underlying SimpleCursorAdapter
            upAdapter = new updateAdapter().execute();
其中一个AsyncTask的Stacktrace(对所有AsyncTask都是相同的):


AsyncTask
在引擎盖下使用。这些线程可能一点也不会消失,因为过于频繁地创建和删除这些线程是一种浪费。一段时间后,如果您创建更多的
AsyncTasks
,您会发现它将停止创建新线程,并重新使用旧线程

更新以解决某些详细信息:

upAdapter = new updateAdapter().execute();
您可能会认为,如果池中有空闲线程,则不会创建新线程,但这并不完全正确。其思想是,有一定数量的线程可以用来处理异步任务。这称为核心池大小。在Android的
AsyncTask
案例中,他们似乎将其设置为5。如果您查看
ThreadPoolExecutor
的文档,它会说:

在方法execute(Runnable)中提交新任务时,如果运行的线程少于corePoolSize,则会创建一个新线程来处理该请求,即使其他工作线程处于空闲状态


还有一个最合适的最大池大小。

歌舞伎所说的是正确的,但我也认为在开始新的任务之前取消任务是一个很好的做法。你可能会有一些奇怪的行为,以防旧任务继续进行。此外,在您的情况下,您不想多次查询数据库,这将是无用的。您可以使用如下方法包装对异步任务的调用:

AsyncDataLoading loaderTask = null;

private void runTask(){
    if (loaderTask!=null && loaderTask.getStatus().compareTo(Status.FINISHED)!=0) {
        loaderTask.cancel(true);
    }
    loaderTask = new AsyncDataLoading();
    loaderTask.execute();
} 
当异步任务完成时,禁用按钮并重新启用它也是一种很好的做法


无论如何,这个解决方案不适合您的体系结构,我对您的代码了解不够。希望它能有所帮助。

我们能看看您正在运行的一些代码吗?您是在每个
AsyncTask
上调用
execute()
,还是仅仅创建对象?您能为那些睡眠
AsynTask
线程发布完整的堆栈跟踪吗?根据我的经验,应该不会有太多的车停在那里。还有,你在哪个Android版本上测试这个呢?@inazaruk Android 2.2。如何获取AsyncTask线程的stacktrace?@@soren.qvist,从stack trace可以清楚地看出@kabuko是正确的。没错,但是如果池中有一些空闲线程,为什么要创建新线程?实际上它不应该这样做。添加了更多细节来解决您的问题。看起来您是对的
AsyncTask
的核心池大小为5(请参阅)。谢谢大家。我总是可以指望StackOverflow:)谢谢你的建议,我不确定我是否理解你发布的代码(AsyncTask对我来说是全新的),AsyncDataLoading似乎不是来自Android库?没问题。AsyncDataLoading只是扩展AsyncTask的类的名称,在您的例子中是“UpdateDapter”…哎哟。。再次通读您的代码,现在就有意义了。谢谢
AsyncDataLoading loaderTask = null;

private void runTask(){
    if (loaderTask!=null && loaderTask.getStatus().compareTo(Status.FINISHED)!=0) {
        loaderTask.cancel(true);
    }
    loaderTask = new AsyncDataLoading();
    loaderTask.execute();
}