Получение java.util.concurrent.RejectedExecutionException из asyncTask на Android - PullRequest
0 голосов
/ 05 января 2012

Я читаю базу данных sqlite в tableLayout. Я не хочу делать это в отдельном потоке вместо долгого ожидания без обновлений пользовательского интерфейса. Поэтому я использовал 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();
        }
    }

и вот AsyncTask

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));
        }
    }
}

Ответы [ 3 ]

2 голосов
/ 12 января 2012

Причина, по которой вы видите это исключение 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 (что означает, что при необходимости Исполнитель создаст не более 128 потоков).

Когда вы превысите 128 потоков и отправите новый экземпляр MyTask с глубиной очереди 10, вы получитеRejectedExecutionException.Это исключение выдается, когда вы насыщаете все доступные потоки, и в очереди больше нет места.

Вы можете легко подтвердить это, получив дамп потока, когда происходит RejectedExecution.

В основном,Вы можете отправить 138 MyTask в любое конкретное время, но как только вы отправите 139+ одновременно (не в течение срока службы приложения), вы столкнетесь с этой проблемой

Редактировать: Я прошел через код больше, и в самой последней версии (фактически начиная с 16 января 2011 г.) эта ошибка никогда не должна возникать.

С любой более старой версией вы столкнетесь с этой проблема .

Короче говоря, если вы обновите свою версию, эта проблема исчезнет, ​​однако каждая задача будет выполняться последовательно, а не одновременно.

1 голос
/ 11 января 2012

Если вы хотите сделать это с помощью AsyncTask, рассмотрите возможность использования publishProgress(), таким образом, каждый элемент будет добавляться при получении из базы данных. Таким образом:

ПРИМЕЧАНИЕ : Учтите, что Song - это класс с атрибутами name, album, artist и time.

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, я настоятельно рекомендую вам перечитать ее документацию для разработчиков Android , поскольку ее концепция немного сложна для понимания, но очень эффективна, когда вы делаете это. Как прокомментировал ваш ответ Romain Guy, вы можете выполнять код пользовательского интерфейса только в методах onPreExecute (), onProgressUpdate () и onPostExecute ().

0 голосов
/ 08 января 2012

Я не думаю, что вам нужно создать один AsyncTask для этого.Вы ничего не получаете из сети или загружаете изображения.Это просто стандартная загрузка.

Я бы ограничил результат в SQL с помощью «limit».

Кроме того, вы делаете это внутри адаптера, верно?Потому что я думаю, что вы добавляете все в список, где вы должны создать представление списка в вашем макете и установить адаптер.Возможно расширение 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"));
    }



    }
...