Пустое чтение списка внутри doInBackground AsyncTask - PullRequest
0 голосов
/ 03 октября 2019

Я пытаюсь прочитать список целых чисел внутри doInBackground из AsyncTask. Когда я передаю список в конструктор AsyncTask, он полон. Но к тому времени, как я доберусь до функции doInBackground, она пуста. Есть идеи?

public class floatingActionButtonClickListener implements View.OnClickListener{

    @Override
    public void onClick(View v) {
        if(mAdapter.getDeleteModeStatus()){
            // Delete items from database
            ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
            new DeleteDatabase().execute(IDsToDelete);

            // Turn FAB back to regular button
            mFAB.setImageResource(R.drawable.baseline_add_white_48); // Turn FAB to delete button

            // Disable delete mode
            mAdapter.exitDeleteMode();

            // Load database
            new LoadDatabase().execute();
        }
        else{
            Intent intent = new Intent(getBaseContext(), AcitivtyJournal.class);
            int journalType = Constants.JOURNALTYPE_FULL;
            intent.putExtra(Constants.JOURNAL_TYPE, journalType);
            startActivity(intent);
        }
    }
}

private class DeleteDatabase extends AsyncTask <ArrayList<Integer>, Void, Void> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mProgressBarHolder.setVisibility(View.VISIBLE);
    }

    @Override
    protected Void doInBackground(ArrayList<Integer>... arrayLists) {
        ArrayList<Integer> IDsToDelete = arrayLists[0];

        AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "JournalEntries")
                .build();

        for(Integer idToDelete : IDsToDelete){
            db.mJournalEntriesDao().deleteCompleteJournalEntry(idToDelete);
        }

        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        mProgressBarHolder.setVisibility(View.GONE);
    }
}

}

Ответы [ 2 ]

1 голос
/ 03 октября 2019

Это не то, как вы используете, а AsyncTask. Вам необходимо объявить параметры и затем получить их в обратном вызове.

Обратите также внимание, что вы пытаетесь получить доступ к одним и тем же данным (IDsToDelete) из двух потоков (Main и Background), по-своему, без надлежащегосинхронизация.

private class DeleteDatabase extends AsyncTask<ArrayList<Integer>, Void, Void> {
    @Override
    protected Void doInBackground(ArrayList<Integer>... arrayLists) {
        ArrayList<Integer> params = arrayLists[0];
        // Do what you need
    }
}

ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);

Когда у вас есть многопоточность, вам нужно искать две вещи:

  • атомарное выполнение операций
  • видимость памяти.

    Существует общая память, и каждый процессор кэширует данные. Когда вы создаете что-то из одного потока, вы не можете просто ожидать, что второй поток просто прочитает это. В вашем случае вы создаете AsyncTask и вставляете параметры из одного потока, но затем вы читаете их в doInBackground из другого. В общем, когда вы проходите через синхронизированный блок или нажимаете переменную (я вообще говорю, потому что я также не до конца понимаю, как работает JVM), поток сбрасывает свой кеш в основную память, а затем читает из нее. Вот как данные передаются. Вот почему лучше использовать фреймворк, потому что фрейм позаботится о правильной публикации ваших данных между потоками. Вы в порядке с неизменными данными, но список не такая вещь. И даже если вы объявите ссылку как неизменную, вы можете увидеть нужный объект из обоих потоков, но данные, которые они содержат, могут быть устаревшими.

Просто чтобы было ясно. Я не говорю, что предыдущий способ не работал. Я говорю, что это по доброй воле. Вы не можете просто обмениваться данными между темами и надеяться, что это сработает.

0 голосов
/ 08 октября 2019

Разобрался. Публикация для людей в будущем, у которых могут возникнуть подобные вопросы.

Довольно странно, что ArrayList<Integer> пустовал, потому что я удалял его в функции mAdapter.exitDeleteMode(); после того, как я вызвал AsyncTask().execute().

Я не знал, что когда я отправлял список на AsyncTask, это был точный адрес списка, а не просто новый список (то есть, пока я не разместил комментарий выше, а затем он щелкнул). Я думаю, что я получил этот ход мышления от C ++ или другого языка. Я не помню, какой именно.

Решение: Решение, которое я нашел, состоит в том, чтобы просто переместить mAdapter.exitDeleteMode() в onPostExecute() вместо того, чтобы использовать его в методе onClick().

Другое потенциальное решение: Я считаю, что другое решение, которое будет работать (но я не проверял), это просто вставить new ArrayList<Integer> () в AsyncTask

...