AsyncTask 一直在等待?

AsyncTask keeps waiting?(AsyncTask 一直在等待?)

本文介绍了AsyncTask 一直在等待?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的一个活动中的一个按钮调用一个 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 一直在等待?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:AsyncTask 一直在等待?