I have a RecyclerView
and FirebaseRecyclerAdapter
with items. Each item has reference to some files in Firebase
storage. each item has download button. I use storageReference.getFile(location)
to download files from firebase storage.
When I click on download button and wait for the download to finish, the checked icon (green icon) is showing correctly at specific position.
My problem is when I download multiple items at same time (when I click on multiple items), the green icon is not displays at appropriate position on every item.
How can I manage multiple download on every item simultaneously so that the green icon can be shown at specific position when specific item download finished?
The code in OnBindViewHolder
behind the download button.
holder.imgDocumentChecker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
holder.imgDocumentChecker.setVisibility(View.GONE);
holder.txtProgress.setVisibility(View.VISIBLE);
holder.progressBar.setVisibility(View.VISIBLE);
final Document item = getItem(holder.getAdapterPosition());
final File parent = fileHelper.parentFolderGenerator(item);
counter = 0;
if (item.getFirebaseStorageFiles() != null && !item.getFirebaseStorageFiles().isEmpty()) {
if (parent.listFiles() == null) {
final String[] files = item.getFirebaseStorageFiles().split("____");
if (files != null && files.length > 0) {
for (int i = 0; i < files.length; i++) {
String fileName = files[i].substring(files[i].lastIndexOf("/") + 1);
String storageFileUrl = Constants.ROOT_FIREBASE_STORAGE_URL + item.getDocFolder() + File.separator + files[i];
if (!parent.exists()) {
parent.mkdirs();
}
File localFile = new File(parent, fileName);
StorageReference storageReference = storage.getReferenceFromUrl(storageFileUrl);
storageReference.getFile(localFile)
.addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
counter++;
int valeur = (100 / files.length) * counter;
holder.progressBar.setProgress(valeur);
holder.txtProgress.setText(valeur + "");
Log.d("progressvalues:", "valeur:"+valeur+"|counter:"+counter+"|lengh:"+files.length);
if (counter == files.length) {
holder.txtProgress.setVisibility(View.GONE);
holder.progressBar.setVisibility(View.GONE);
holder.imgDocumentChecker.setVisibility(View.VISIBLE);
holder.imgDocumentChecker.setImageResource(R.drawable.done_ic);
}
}
}).addOnProgressListener(new OnProgressListener<FileDownloadTask.TaskSnapshot>() {
@Override
public void onProgress(FileDownloadTask.TaskSnapshot taskSnapshot) {
double progress = (100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount();
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
holder.txtProgress.setVisibility(View.GONE);
holder.progressBar.setVisibility(View.GONE);
}
});
}
}
} else {
startDocumentContentActivity(item, getRef(position));
}
}
}
});
Please help.
Like mentioned in the comments this request shouldn't be done in the RecyclerView.Adapter
, and should definitely not be made in the onBindViewHolder
.
You should abstract this to a separate class, a Presenter
or the framework's own ViewModel
, that being said:
Once that request is made and the new data comes in, you should update your adapter's data model
and notify of these changes.
Reporting a click (that would eventually trigger a request) should be done via an interface where you could have your Adapter
:
public interface Listener {
void onItemClicked(YourModelPojo item);
}
And your Activity/Fragment/Presenter however abstract you want to do would implement this Listener interface.
So your adapter's
holder.imgDocumentChecker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View view) {
// Update the UI the request is being made and report to listener
listener.onItemClicked(data.get(getAdapterPosition()));
}
Then your adapter should also have an update item on the adapter's data and notify of this change. Since your model changed your bindViewHolder
would update the UI correctly.
Of course, you have to implement these UI changes (data downloading/updated/etc.)
I've written some articles that you can rely on (with open source code):