【问题标题】:Getting java.util.concurrent.RejectedExecutionException from asyncTask on android从android上的asyncTask获取java.util.concurrent.RejectedExecutionException
【发布时间】:2012-01-05 00:27:08
【问题描述】:

我正在将一个 sqlite 数据库读入 tableLayout。我不想在单独的线程中执行此操作,而不是在没有 ui 更新的情况下长时间等待。所以我使用了一个 AsyncTask 来做一些工作并发布结果。然而,我的列表中只有大约 1/4 的项目实际上进入了 TableLayout。没有 AsyncTask 也能正常工作。列表中的大多数项目都会引发错误(我发现)java.util.concurrent.RejectedExecutionException。我不确定这是为什么。这是我的代码。

myDB.execSQL("CREATE TABLE IF NOT EXISTS "
                + TableName
                + " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");

        Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);         

        c.moveToFirst();
        if (c != null) {
            int color = 0xFFdfe8ea;
            this.startManagingCursor(c);
            // Loop through all Results
            do {
                try{
                    MyAsyncTask aTask = new MyAsyncTask();
                    String[]strings= {c.getString(c.getColumnIndex("title")),c.getString(c.getColumnIndex("artist")),c.getString(c.getColumnIndex("time")),c.getString(c.getColumnIndex("album")),""+color};
                    aTask.execute(strings);
                }catch(Exception e){
                    Log.w("****", e);
                }
        if (color == 0xFFdfe8ea) {
                    color = 0xFFf2f8fa;
                } else {
                    color = 0xFFdfe8ea;
                }
            } while (c.moveToNext());
        }

    } catch (SQLException e) {
        Log.e("****", e.toString());
    } finally {
        if (myDB != null) {
            myDB.close();
        }
    }

这里是异步任务

class MyAsyncTask extends AsyncTask<String, Void, View> {
    @Override
    protected View doInBackground(String... params) {
        int color = Integer.parseInt(params[4]);

        TableRow tr = new TableRow(MainActivity.this);
        tr.setLayoutParams(new LayoutParams(
                LayoutParams.FILL_PARENT,
                LayoutParams.WRAP_CONTENT));

        TextView space = new TextView(MainActivity.this);
        space.setText("");
        space.setBackgroundColor(color); //0xFFf2f8fa alternating
        space.setSingleLine();
        space.setPadding(2, 2, 2, 2);
        space.setGravity(Gravity.LEFT);
        space.setTextColor(0xFF000000);
        space.setLayoutParams(new LayoutParams(
                findViewById(R.id.spaceColumn).getWidth(),
                LayoutParams.WRAP_CONTENT));

        /* Create a Button to be the row-content. */
        TextView title = new TextView(MainActivity.this);
        title.setText(params[0]);
        title.setBackgroundColor(color); //0xFFf2f8fa alternating
        title.setSingleLine();
        title.setPadding(2, 2, 2, 2);
        title.setGravity(Gravity.LEFT);
        title.setTextColor(0xFF000000);
        title.setEllipsize(TruncateAt.END);
        title.setLayoutParams(new LayoutParams(
                0,
                LayoutParams.WRAP_CONTENT, 1));

        /* Create a Button to be the row-content. */
        TextView artist = new TextView(MainActivity.this);
        artist.setText(params[1]);
        artist.setBackgroundColor(color); //0xFFf2f8fa alternating
        artist.setSingleLine();
        artist.setPadding(2, 2, 2, 2);
        artist.setGravity(Gravity.LEFT);
        artist.setTextColor(0xFF000000);
        artist.setEllipsize(TruncateAt.END);
        artist.setLayoutParams(new LayoutParams(
                0,
                LayoutParams.WRAP_CONTENT, 1));

        /* Create a Button to be the row-content. */
        TextView time = new TextView(MainActivity.this);
        time.setText(params[2]);
        time.setBackgroundColor(color); //0xFFf2f8fa alternating
        time.setSingleLine();
        time.setPadding(2, 2, 2, 2);
        time.setGravity(Gravity.LEFT);
        time.setTextColor(0xFF000000);
        time.setLayoutParams(new LayoutParams(
                findViewById(R.id.timeColumn).getWidth(),
                LayoutParams.WRAP_CONTENT));

        /* Create a Button to be the row-content. */
        TextView album = new TextView(MainActivity.this);
        album.setText(params[3]);
        album.setBackgroundColor(color); //0xFFf2f8fa alternating
        album.setSingleLine();
        album.setPadding(2, 2, 2, 2);
        album.setGravity(Gravity.LEFT);
        album.setTextColor(0xFF000000);
        album.setEllipsize(TruncateAt.END);
        album.setLayoutParams(new LayoutParams(
                0,
                LayoutParams.WRAP_CONTENT, 1));

        /* Add Button to row. */
        tr.addView(space);
        tr.addView(title);
        tr.addView(artist);
        tr.addView(time);
        tr.addView(album);

        /* Add row to TableLayout. */
        return tr;
    }

    @Override
    protected void onPostExecute(View tr) {
        ((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
                        LayoutParams.FILL_PARENT,
                        LayoutParams.WRAP_CONTENT));
    }

    @Override
    protected void onPreExecute() {
    }
 }

作为参考,这是我修复它的方法。

class MyAsyncTask extends AsyncTask<Void, Song, Void> {

    @Override
    protected Void doInBackground(Void... params) {

        SQLiteDatabase myDB = openOrCreateDatabase("DatabaseName", MODE_PRIVATE, null);
        String TableName = "songs";

        myDB.execSQL("CREATE TABLE IF NOT EXISTS "
                + TableName
                + " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");

        Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);

        c.moveToFirst();
        int filepathIndex=c.getColumnIndex("filepath");
        int titleIndex=c.getColumnIndex("title");
        int artistIndex=c.getColumnIndex("artist");
        int albumIndex=c.getColumnIndex("album");
        int timeIndex=c.getColumnIndex("time");
        int playcountIndex=c.getColumnIndex("playcount");

        if (c != null) {
            int color = 0xFFdfe8ea;
         //   this.startManagingCursor(c);
            // Loop through all Results
            do {
                Song song = new Song(c.getString(filepathIndex),c.getString(titleIndex),c.getString(artistIndex),c.getString(albumIndex),c.getString(timeIndex),c.getInt(playcountIndex),color);
                // Add to song the data from your cursor
                publishProgress(song);

                if (color == 0xFFdfe8ea) {
                    color = 0xFFf2f8fa;
                } else {
                    color = 0xFFdfe8ea;
                }
            } while (c.moveToNext());
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void item) {
    }

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected void onProgressUpdate(Song... items) {
        for (Song song : items) {
            TableRow tr = new TableRow(MainActivity.this);
            tr.setLayoutParams(new LayoutParams(
                    LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));

            TextView space = new TextView(MainActivity.this);
            space.setText("");
            space.setBackgroundColor(song.color); //0xFFf2f8fa alternating
            space.setSingleLine();
            space.setPadding(2, 2, 2, 2);
            space.setGravity(Gravity.LEFT);
            space.setTextColor(0xFF000000);
            space.setLayoutParams(new LayoutParams(
                    findViewById(R.id.spaceColumn).getWidth(),
                    LayoutParams.WRAP_CONTENT));

            /* Create a Button to be the row-content. */
            TextView title = new TextView(MainActivity.this);
            title.setText(song.title);
            title.setBackgroundColor(song.color); //0xFFf2f8fa alternating
            title.setSingleLine();
            title.setPadding(2, 2, 2, 2);
            title.setGravity(Gravity.LEFT);
            title.setTextColor(0xFF000000);
            title.setEllipsize(TruncateAt.END);
            title.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Create a Button to be the row-content. */
            TextView artist = new TextView(MainActivity.this);
            artist.setText(song.artist);
            artist.setBackgroundColor(song.color); //0xFFf2f8fa alternating
            artist.setSingleLine();
            artist.setPadding(2, 2, 2, 2);
            artist.setGravity(Gravity.LEFT);
            artist.setTextColor(0xFF000000);
            artist.setEllipsize(TruncateAt.END);
            artist.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Create a Button to be the row-content. */
            TextView time = new TextView(MainActivity.this);
            time.setText(song.time);
            time.setBackgroundColor(song.color); //0xFFf2f8fa alternating
            time.setSingleLine();
            time.setPadding(2, 2, 2, 2);
            time.setGravity(Gravity.LEFT);
            time.setTextColor(0xFF000000);
            time.setLayoutParams(new LayoutParams(
                    findViewById(R.id.timeColumn).getWidth(),
                    LayoutParams.WRAP_CONTENT));

            /* Create a Button to be the row-content. */
            TextView album = new TextView(MainActivity.this);
            album.setText(song.album);
            album.setBackgroundColor(song.color); //0xFFf2f8fa alternating
            album.setSingleLine();
            album.setPadding(2, 2, 2, 2);
            album.setGravity(Gravity.LEFT);
            album.setTextColor(0xFF000000);
            album.setEllipsize(TruncateAt.END);
            album.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Add Button to row. */
            tr.addView(space);
            tr.addView(title);
            tr.addView(artist);
            tr.addView(time);
            tr.addView(album);

            // Add the row to the table
            ((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
                    LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));
        }
    }
}

【问题讨论】:

  • 你不应该从 UI 线程之外创建视图。您可以在 doInBackground() 中执行 SQL 查询,但在 onPostExecute() 中创建视图。
  • @ghostbust555 你用的是什么版本?

标签: android xml multithreading layout android-asynctask


【解决方案1】:

您看到此 RejectedExceutionException 的原因几乎可以肯定是因为您提交了太多请求。

我刚刚进入了 AsyncTask 的代码,我注意到:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;

private static final BlockingQueue<Runnable> sPoolWorkQueue =
      new LinkedBlockingQueue<Runnable>(10);

/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

这将构建一个有界的 LinkedBlockingQueue。边界最多 10 个元素。这 我看到的 MAXIMUM_POOL_SIZE 是 128(这意味着如果需要,Executor 最多会创建 128 个线程)。

一旦超过 128 个线程并提交到队列深度为 10 的新 MyTask 实例,您将收到 RejectedExecutionException。当您使所有可用线程饱和并且队列中没有更多空间时,将引发此异常。

您可以通过在 RejectedExecution 发生时获取线程转储来轻松确认这一点。

基本上,您可以在任何特定时间提交 138 个 MyTask,但是一旦您同时提交 139 个以上(不在应用程序的生命周期内),您就会遇到此问题

编辑:我查看了更多代码,最新版本(实际上是从 2011 年 1 月 16 日开始)永远不会发生此错误。

使用任何旧版本,您都会遇到这个issue

简而言之,如果你升级你的版本,这个问题就会消失,但是每个任务将被串行执行而不是同时执行。

【讨论】:

  • 这个错误发生在我只调用 10 个 AsyncTasks 时,我使用的是相当新的版本,不过我会尝试更新并报告。
  • 能否包含堆栈跟踪
【解决方案2】:

如果您想使用 AsyncTask 执行此操作,请考虑使用 publishProgress(),这样每个项目都会在从数据库中获取时添加。这样:

注意:考虑Song 是一个具有namealbumartisttime 属性的类。

class MyAsyncTask extends AsyncTask<Void, Song, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        myDB.execSQL("CREATE TABLE IF NOT EXISTS "
            + TableName
            + " (_id INTEGER PRIMARY KEY, filepath TEXT UNIQUE, title TEXT, artist TEXT, album TEXT, time TEXT, playcount NUMERIC);");

        Cursor c = myDB.rawQuery("SELECT * FROM " + TableName, null);         

        c.moveToFirst();
        if (c != null) {
            int color = 0xFFdfe8ea;
            this.startManagingCursor(c);
            // Loop through all Results
            do {
                Song song = new Song();
                // Add to song the data from your cursor
                publishProgress(song);
            } while (c.moveToNext());
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void item) {
    }

    @Override
    protected void onPreExecute() {
    }       

    @Override
    protected void onProgressUpdate(Song... items) {
        for (Song song : items) {    
            TableRow tr = new TableRow(MainActivity.this);
            tr.setLayoutParams(new LayoutParams(
                    LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));

            TextView space = new TextView(MainActivity.this);
            space.setText("");
            space.setBackgroundColor(color); //0xFFf2f8fa alternating
            space.setSingleLine();
            space.setPadding(2, 2, 2, 2);
            space.setGravity(Gravity.LEFT);
            space.setTextColor(0xFF000000);
            space.setLayoutParams(new LayoutParams(
                    findViewById(R.id.spaceColumn).getWidth(),
                    LayoutParams.WRAP_CONTENT));

            /* Create a Button to be the row-content. */
            TextView title = new TextView(MainActivity.this);
            title.setText(song.getTitle());
            title.setBackgroundColor(color); //0xFFf2f8fa alternating
            title.setSingleLine();
            title.setPadding(2, 2, 2, 2);
            title.setGravity(Gravity.LEFT);
            title.setTextColor(0xFF000000);
            title.setEllipsize(TruncateAt.END);
            title.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Create a Button to be the row-content. */
            TextView artist = new TextView(MainActivity.this);
            artist.setText(song.getArtist());
            artist.setBackgroundColor(color); //0xFFf2f8fa alternating
            artist.setSingleLine();
            artist.setPadding(2, 2, 2, 2);
            artist.setGravity(Gravity.LEFT);
            artist.setTextColor(0xFF000000);
            artist.setEllipsize(TruncateAt.END);
            artist.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Create a Button to be the row-content. */
            TextView time = new TextView(MainActivity.this);
            time.setText(song.getTime());
            time.setBackgroundColor(color); //0xFFf2f8fa alternating
            time.setSingleLine();
            time.setPadding(2, 2, 2, 2);
            time.setGravity(Gravity.LEFT);
            time.setTextColor(0xFF000000);
            time.setLayoutParams(new LayoutParams(
                    findViewById(R.id.timeColumn).getWidth(),
                    LayoutParams.WRAP_CONTENT));

            /* Create a Button to be the row-content. */
            TextView album = new TextView(MainActivity.this);
            album.setText(song.getAlbum());
            album.setBackgroundColor(color); //0xFFf2f8fa alternating
            album.setSingleLine();
            album.setPadding(2, 2, 2, 2);
            album.setGravity(Gravity.LEFT);
            album.setTextColor(0xFF000000);
            album.setEllipsize(TruncateAt.END);
            album.setLayoutParams(new LayoutParams(
                    0,
                    LayoutParams.WRAP_CONTENT, 1));

            /* Add Button to row. */
            tr.addView(space);
            tr.addView(title);
            tr.addView(artist);
            tr.addView(time);
            tr.addView(album);

            // Add the row to the table
            ((TableLayout) findViewById(R.id.tableLayout)).addView(tr, new TableLayout.LayoutParams(
                            LayoutParams.FILL_PARENT,
                            LayoutParams.WRAP_CONTENT));
        }
    }
 }

我相信你错误地理解了 AsyncTask 背后的概念,我强烈建议你重新阅读its documentation at Android Developers,因为它的概念有点难以理解,但当你这样做时非常强大。正如 Romain Guy 对您的回答所评论的那样,您只能在 onPreExecute()、onProgressUpdate() 和 onPostExecute() 方法上执行 UI 代码。

【讨论】:

  • 要清楚,publishUpdate(song) 应该是 publishProgress(song) 正确吗?
  • 你有没有因为你把这个查询放在 asyncTask 中而注意到任何“减速”?你能看看我的问题stackoverflow.com/questions/15224298/…10q
【解决方案3】:

我认为您不需要为此创建一个 AsyncTask。您没有从网络中获取任何内容或下载图像。它只是标准加载。

我会用'limit'限制SQL中的结果。

另外,您是在适配器内部进行的,对吗?因为我认为您正在将所有内容添加到列表中,您应该在布局中创建一个列表视图并设置一个适配器。也许扩展 BaseAdapter。

每个适配器都有一个名为 getView 的便捷方法,该方法仅在可见时才会被调用,并且应该有助于解决您的问题。

这是一个适配器的例子:

public class MyAdapter extends BaseAdapter {

    private Context context = null;
    private Cursor cursor;

    public MyAdapter(Context context){

        this.context = context;     
        SQLiteDatabase db = DatabaseHelper.getInstance(context).getReadableDatabase();              
        this.cursor = db.query("YOUR QUERY");

    }

    @Override
    public int getCount() {
        return this.cursor.getCount();
    }


    public Cursor getCursor() {
        return cursor;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LinearLayout row;

        try {           
        cursor.moveToPosition(position);

        if (convertView == null) {      
            row = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.myRowLayout, parent, false);
            } else {
            row = (LinearLayout) convertView;
            }

        TextView name = (TextView) row.findViewById(R.id.myLayoutId);
        name.setText(cursor.getString(cursor.getColumnIndex("your column")));

        } catch (Exception e) {
            row = null;
            Log.e(LOG_TAG, "" + e.getMessage());
            e.printStackTrace();
        }

        return row;

    }

    @Override
    public MoneyCurrency getItem(int position) {        
        this.cursor.moveToPosition(position);
        long id = this.cursor.getLong(this.cursor.getColumnIndex("your column id")); 
        return new Object.read(id, context, null); //Return whatever you want to show in that row. This is used if you want to use onClick listeners or menus
    }

    @Override
    public long getItemId(int position) {
        this.cursor.moveToPosition(position);
        return this.cursor.getLong(this.cursor.getColumnIndex("your id column"));
    }



    }

【讨论】:

  • 我使用 TableLayout 和 TableRows 而不是 listView(虽然我正在考虑以某种方式切换到 listview)但我希望它是一个单独的线程,这样当有一个非常大的数据库时你不会看到黑色屏幕15秒,表格将添加一行然后显示该行并重复
  • 您可以为列表视图中的每个项目设置一个 TableLayout。但请注意,您是在 AsyncTask 之外查询游标,因此即使您使用适配器或运行进程来填充表,也会发生这种情况。仅使用列表视图效率更高。如果数据库太大,使用列表视图或适配器线程不会有太大帮助,因为您可能需要以任何一种方式限制它。您想在单独的线程中执行的操作将在适配器的 getView 内工作。有意义吗?
猜你喜欢
  • 1970-01-01
  • 2012-12-12
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多