Android ProgressBar en ListView mientras usa DownloadManager
Tengo un ListView en el que cada elemento representa un archivo PDF. Cuando el usuario hace clic en un elemento, la aplicación debe descargar el archivo en el almacenamiento externo. Ahora la descarga no funciona correctamente, pero esa no es la cuestión. Quiero que aparezca una barra de progreso, estilo rueda giratoria, junto a cada elemento de la lista mientras se descarga el archivo.
Mi problema es: no puedo encontrar cómo hacer que aparezca la rueca. Antes del Administrador de descargas lo probé con una AsyncTask y la rueda giratoria funcionó.
Aquí está mi código:
CategoryActivity.java (Actividad de ListView)
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Récupère les valeurs depuis ListItem
udl = ((TextView) view.findViewById(R.id.udl)).getText().toString();
// This is the spinning wheel
loader = ((ProgressBar) view.findViewById(R.id.spinWheel2));
filepath = dirpath + udl + ".pdf";
File file = new File(filepath);
if (file.exists()) {
// If the file exists, I open it
}else{ // Else I download it
// Setting the spinning wheel to VISIBLE
loader.setVisibility(View.VISIBLE);
SharedPreferences codeSaveUrl = getSharedPreferences(PREFS_TEXT,Context.MODE_PRIVATE);
url2 = codeSaveUrl.getString("defaut", ""); // Code Organisation
// Constructing the uriString
uri = url10 + url2 + "&file=" + udl ;
Uri myuri = Uri.parse(uri);
DownloadManager mgr=(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
mgr.enqueue(new DownloadManager.Request(myuri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(udl + ".pdf")
.setDescription("Téléchargement en cours")
.setDestinationInExternalPublicDir("/Protocols/", (udl+".pdf"))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE));
// Hiding the spinning wheel
loader.setVisibility(View.GONE);
}
}
Tenga en cuenta que si no hago que la rueca desaparezca, siempre será visible después de hacer clic en el elemento. Con la línea para ocultarlo, ni siquiera aparece.
EDITAR:
Agregué un BroadcastReceiver.
Pon estas dos líneas en onCreate ():
final DownloadManager mgr=(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
Y agregó esto:
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
loader.setVisibility(View.GONE);
}
};
@Override
public void onDestroy(){
super.onDestroy();
unregisterReceiver(onComplete);
}
EDITAR 2: Ok, aquí hay algunos cambios que hice:
Guardo el id de la descarga en una variable:
lastDownload = mgr.enqueue(new DownloadManager.Request(myuri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(udl + ".pdf")
.setDescription("Téléchargement en cours")
.setDestinationInExternalPublicDir("/Protocols/", (udl+".pdf"))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED));
Dependiendo del estado de la descarga, quiero hacer cosas diferentes:
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
Cursor c = mgr.query(new DownloadManager.Query().setFilterById(lastDownload));
if(c.moveToFirst()){
int x = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch(x){
case DownloadManager.STATUS_PAUSED:
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_RUNNING:
break;
case DownloadManager.STATUS_SUCCESSFUL:
loader.setVisibility(View.GONE);
break;
case DownloadManager.STATUS_FAILED:
//TODO: retry download
break;
}
}
}
};
El problema es que la rueca solo se oculta para el último elemento en el que se hizo clic en la vista de lista. Intenté con el modo de depuración, pero el programa tiene un comportamiento correcto (lo que significaloader.setVisibility(View.GONE)
se llama para cada descarga). No sé por qué la rueca no se ocultará, excepto por el último elemento en el que se hizo clic.
EDITAR: 3 Sé por qué la rueca no se ocultará, excepto por el último elemento en el que se hizo clic.
Cuando hago clic en varios elementos, lastDownload toma la identificación del último en el que se hizo clic. Por lo tanto, en el receptor de difusión, hace el caso del último elemento en el que se hizo clic multiplicado por el número de elementos en los que se hizo clic.
Intenté cambiar lastDownload en una matriz / tabla de longs y compararlo con referenceId, que creo que es la identificación contenida en la intención.
Aquí está el nuevo código (y = 0 y ld es la cantidad de elementos en los que se hizo clic):
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if(y <ld){
if(lastDownload[y] == referenceId){
Cursor c = mgr.query(new DownloadManager.Query().setFilterById(lastDownload[y]));
if(c.moveToFirst()){
int x = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch(x){
case DownloadManager.STATUS_PAUSED:
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_RUNNING:
break;
case DownloadManager.STATUS_SUCCESSFUL:
loader.setVisibility(View.GONE); // This loader is the one of the last item clicked
break;
case DownloadManager.STATUS_FAILED:
//TODO: retry download
break;
}
}
y=y+1;
}
}
}
};
No escribí la parte donde puse las variables de nuevo a 0, pero por ahora el código funciona más o menos como se esperaba. El único problema que queda es que la rueca que hago desaparecer es la rueca del último elemento en el que se hizo clic. Y sé por qué. Porque esta línea:loader = ((ProgressBar) view.findViewById(R.id.spinWheel2));
se encuentra en laonItemClicked
método. No creo que pueda ponerlo en ningún otro lugar porque la vista en la que se encuentra no es la vista de la actividad.
En pocas palabras: debo encontrar una manera de acceder a la barra de progreso del elemento / vista en el que hice clic, sabiendo que puedo hacer clic en varios elementos antes de que el primero llegue al receptor de transmisión.
EDITAR: 4 Ok, entonces hice esto:
y
,z
yld
están configurados para0
al principio.
Cuando se hace clic en un elemento:
// Loader of the clicked item is made visible
loader[z].setVisibility(View.VISIBLE);
// Construction of the URL
SharedPreferences codeSaveUrl = getSharedPreferences(PREFS_TEXT,Context.MODE_PRIVATE);
url2 = codeSaveUrl.getString("defaut", ""); // Organization code
uri = url10 + url2 + "&file=" + udl ;
// URL parse to URI
Uri myuri = Uri.parse(uri);
// Enqueue file to downloads, with notification. Storage of download id in a table
lastDownload[ld] = mgr.enqueue(new DownloadManager.Request(myuri)
.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI |DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(udl + ".pdf")
.setDescription("Téléchargement en cours")
.setDestinationInExternalPublicDir("/Protocols/", (udl+".pdf"))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE));
// Increment variables for next downloads
ld=ld+1;
z=z+1;
Receptor de radiodifusión :
// Broadcast Receiver called when a download is finished
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
// referenceId is the download's id for which the method is called
long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// If y (=0 at the beginning) is inferior to the number of downloads
if(y <ld){
// If the id of the download corresponds to the one for which the method is called
if(lastDownload[y] == referenceId){
// We define a cursor depending on the id
Cursor c = mgr.query(new DownloadManager.Query().setFilterById(lastDownload[y]));
if(c.moveToFirst()){
// Download status recovery
int x = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch(x){
// If download is paused, pending or running, we do nothing
case DownloadManager.STATUS_PAUSED:
case DownloadManager.STATUS_PENDING:
case DownloadManager.STATUS_RUNNING:
break;
// If file has successfully been downloaded, loader is hidden
case DownloadManager.STATUS_SUCCESSFUL:
loader[y].setVisibility(View.GONE);
// Increment y to go to next download
y=y+1;
break;
// If download failed, it is retried
case DownloadManager.STATUS_FAILED:
//TODO: retry download
break;
}
}
}
}
}
};
Funciona bien, excepto cuando se hace clic en un elemento de un archivo pequeño mientras se descarga un archivo grande. El archivo pequeño tiene prioridad y el administrador de descargas ya no sigue el orden de las tablas, lo que hace que la rueda de carga no desaparezca.
EDITAR: 5
Encontré una manera de hacer lo que quería, ver mi respuesta.
Gracias por tu ayuda.