Звучит глупо, верно?
У меня есть RecyclerView с карточками предметов. Эти карты имеют кнопку, которая отображает всплывающее окно со списком «вложений» в другом RecyclerView. Эти карты вложений имеют кнопку, с помощью которой вы можете загрузить их, и процесс загрузки должен отображаться на индикаторе выполнения.
Теперь я не могу найти правильный способ обновления индикатора выполнения при выполнении параллельных асинхронных загрузок.
По сути, у меня есть asyncTask с прослушивателем прогресса, который обновляет поле прогресса в объекте AttachmentData (данные, связанные с картами вложений). Предполагается, что владелец может прочитать ход выполнения AttachmentData и обновить индикатор выполнения ...
... во всплывающем окне элемента в представлении переработчика.
Моя проблема в том, что всякий раз, когда я запускаю новый asyncTask поверх других AsyncTask, последний asyncTask перехватывает весь прогресс предыдущих, и вместо трех вложений, показывающих их индивидуальный прогресс, у меня есть два вложения, показывающие их замороженный прогресс (вплоть до щелчка по третьему вложению), а третье вложение показывает прогресс трех вложений, обновляя каждый раз, когда одно из них обновляет свой собственный прогресс.
Это довольно запутанно.
Дело в том, что у меня есть основания подозревать, что это не имеет никакого отношения к RecyclerView, поскольку отправляемые мной уведомления ведут себя именно так.
Все происходит при привязке данных в ViewHolder
public <T extends DownloadableData> void bindData(T data, ItemProgressListener ipl) {
this.data = data;
this.ipl = ipl;
//....
button.setOnClickListener(v->openDoc());
//....
}
public void openDoc(){
data.pdfStatus = PDF_DOWNLOADING;
NotificationCompat.Builder builder = new NotificationCompat.Builder(parentFragment.getActivity(), CHANNEL_ID)
.setSmallIcon(R.drawable.logo_white)
.setContentTitle("Downloading " + data.title)
.setContentText("Current Progress: " + data.progress + " %")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Current Progress: " + data.progress + " %"))
.setAutoCancel(false);
int PROGRESS_MAX = 100;
builder.setProgress(PROGRESS_MAX, 0, false);
int notificationId = Integer.parseInt(data.uuid);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, builder.build());
CloudManager.PaperDownloader pd = new CloudManager.PaperDownloader() {
@Override
public String getFilePath() {
return data.filepath;
}
@Override
public void progressUpdate(Integer... values) {
data.pdfStatus = PDF_DOWNLOADING;
data.setProgress(values[0]);
if ((values[0] % 5 == 1 || values[0] == 100) && data.previousProgress < data.progress) {
if (ipl != null)
ipl.onItemProgressChanged(position, data);
builder.setContentText("Current Progress: " + values[0] + " %")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Current Progress: " + values[0] + " %"))
.setProgress(PROGRESS_MAX, values[0], false);
notificationManager.notify(notificationId, builder.build());
}
}
@Override
public void downloadSuccess(Integer... positions) {
data.pdfStatus = PDF_DOWNLOADED;
data.setProgress(100);
if (ipl != null)
ipl.onItemProgressChanged(position, data);
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Current Progress: 100 %"))
.setProgress(0, 0, false);
notificationManager.notify(notificationId, builder.build());
notificationManager.cancel(notificationId);
}
@Override
public void downloadCancelled(String errorMessage) {
data.pdfStatus = PDF_DOWNLOAD_CANCELLED;
data.setProgress(-1);
if (ipl != null)
ipl.onItemProgressChanged(position, data);
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Operation has been cancelled!:\n" + errorMessage))
.setProgress(0, 0, false);
notificationManager.notify(notificationId, builder.build());
}
@Override
public void downloadFailed(String errorMessage) {
data.pdfStatus = PDF_DOWNLOAD_FAILED;
data.setProgress(-1);
if (ipl != null)
ipl.onItemProgressChanged(position, data);
builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Operation has been cancelled!:\n" + errorMessage))
.setProgress(0, 0, false);
notificationManager.notify(notificationId, builder.build());
}
};
try {
String finalPath = cloudManager.getRemoteFilePath(data.filepath, true);
cloudManager.getArticlePdfDownloader(pd)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, finalPath);
} catch (NullPointerException npe) {
npe.printStackTrace();
parentFragment.alert(context.getString(R.string.alert_cloud_not_set));
}
}
Для ясности, "ipl" - это еще один интерфейс, переданный адаптером держателю, в попытке от меня обновить как можно меньше карт в процессе загрузки. Самый ленивый / самый глупый способ определения ipl:
adapter.setOnItemProgressListener((position, data)->adapter.notifyDataSetChanged());
Наконец, bindData вызывается адаптером
@Override
public void onBindViewHolder(@NonNull AbstractDownloadableHolder holder, int position) {
DownloadableData currentPaper = this.dataList.get(position);
holder.bindData(currentPaper, ipl);
}