问题描述
我的一个活动中的一个按钮调用一个 AsyncTask,它更新 ListView 的 SimpleCursorAdapter 的底层 Cursor.每次单击按钮时,都会为 AsyncTask 添加一个新线程并且任务完成(进入等待"状态).如果我单击按钮 5 次或更多次,则 5 个 AsyncTask 最终会以等待"状态坐在那里.这是正常的还是我在某处有内存泄漏?
A button in one of my activities calls an AsyncTask that updates the underlying Cursor for a ListView's SimpleCursorAdapter. Everytime I click the button, a new thread for the AsyncTask is added and the task completes (goes to 'wait' status). If I click the button 5 or more times, 5 AsyncTasks ends up sitting there with 'wait' status. Is this normal or do I have a memory leak somewhere?
异步任务
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());
}
}
以及我的 onCreate 中调用任务的代码(首次加载 Activity 时):
upAdapter = new updateAdapter().execute();
在按钮 onClickListener 中:
And in the button onClickListener:
// Reset wod_id
_wod_id = -1;
// Update the underlying SimpleCursorAdapter
upAdapter = new updateAdapter().execute();
其中一个 AsyncTask 的 Stacktrace(对所有这些都是一样的):
Stacktrace of one of the AsyncTask (it's the same for all of them):
Object.wait(long, int) line: not available [native method]
Thread.parkFor(long) line: 1535
LangAccessImpl.parkFor(long) line: 48
Unsafe.park(boolean, long) line: 317
LockSupport.park() line: 131
AbstractQueuedSynchronizer$ConditionObject.await() line: 1996
LinkedBlockingQueue.take() line: 359
ThreadPoolExecutor.getTask() line: 1001
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1061
ThreadPoolExecutor$Worker.run() line: 561
Thread.run() line: 1096
推荐答案
AsyncTask
在幕后使用了 ThreadPoolExecutor
.这些线程可能暂时不会消失,因为过于频繁地创建和拆除这些线程是一种浪费.一段时间后,如果您创建更多 AsyncTasks
,您会发现它会停止创建新线程并重新使用旧线程.
AsyncTask
under the hood uses a ThreadPoolExecutor
. Those threads might not go away for a bit because it'd be a waste to keep creating and tearing down those threads too often. After a while if you create more AsyncTasks
you'll find that it'll stop creating new threads and it'll re-use the old ones.
更新以解决一些细节:
您会认为如果池中有空闲线程,它就不会创建新线程,但这并不完全正确.这个想法是有一定数量的线程可以用来处理异步任务.这称为核心池大小.在 Android 的 AsyncTask
案例中,他们似乎已将其设置为 5.如果您查看 ThreadPoolExecutor
的文档,它说:
You would think that if there are free threads in the pool, it wouldn't create new ones, but this isn't exactly true. The idea is that there's a certain number of threads that are useful to have around to keep processing asynchronous tasks. This is called the core pool size. In Android's AsyncTask
case, they seem to have set it to 5. If you look at the documentation for ThreadPoolExecutor
it says:
当一个新任务在方法 execute(Runnable) 中提交,并且少于 corePoolSize 的线程正在运行时,即使其他工作线程空闲,也会创建一个新线程来处理请求.
When a new task is submitted in method execute(Runnable), and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle.
还有一个合适的最大值,称为最大池大小.
There's also a maximum fittingly called the maximum pool size.
这篇关于AsyncTask 一直在等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!