ProgressBar do Android no ListView ao usar o DownloadManager
Eu tenho um ListView no qual cada item representa um arquivo PDF. Quando o usuário clica em um item, o aplicativo deve fazer o download do arquivo no armazenamento externo. Agora, o download não funciona corretamente, mas essa não é a questão. Quero que um ProgressBar, estilo de roda giratória, apareça ao lado de cada item da lista enquanto o arquivo é baixado.
Meu problema é: não consigo encontrar como fazer a roda giratória aparecer. Antes do Download Manager, eu tentei com um AsyncTask e a roda giratória funcionou.
Aqui está o meu código:
CategoryActivity.java (Atividade do 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);
}
}
Observe que, se eu não fizer a roda giratória desaparecer, ela sempre estará visível após o clique no item. Com a linha para ocultá-lo, ele nem aparece.
EDIT:
Eu adicionei um BroadcastReceiver.
Coloque essas duas linhas no onCreate ():
final DownloadManager mgr=(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
E acrescentou isso:
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
loader.setVisibility(View.GONE);
}
};
@Override
public void onDestroy(){
super.onDestroy();
unregisterReceiver(onComplete);
}
EDIT 2: Ok, então aqui estão algumas mudanças que eu fiz:
Salvei o ID do download em uma variável:
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));
Dependendo do status do download, quero fazer coisas 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;
}
}
}
};
O problema é que a roda giratória oculta apenas o último item clicado no listView. Eu tentei com o modo de depuração, mas o programa tem um comportamento correto (ou seja,loader.setVisibility(View.GONE)
é chamado para cada download). Não sei por que a roda giratória não se oculta, exceto o último item clicado.
EDIT: 3 Eu sei por que a roda giratória não se esconde, exceto pelo último item clicado.
Quando clico em vários itens, lastDownload leva o ID do último clicado. Portanto, no receptor de transmissão, o caso do último item clicado é multiplicado pelo número de itens clicados.
Tentei alterar lastDownload em uma matriz / tabela de longos e compará-lo com referenceId, que acredito ser o ID contido na intenção.
Aqui está o novo código (y = 0 e ld é o número de itens clicados):
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;
}
}
}
};
Não escrevi a parte em que coloquei as variáveis de volta em 0, mas, por enquanto, o código funciona como esperado. O único problema que resta é que a roda giratória que faço desaparecer é a roda giratória do último item clicado. E eu sei porque. Porque esta linha:loader = ((ProgressBar) view.findViewById(R.id.spinWheel2));
está localizado noonItemClicked
método. Acho que não posso colocá-lo em nenhum outro lugar porque a visão em que ela está não é a visão da atividade.
Para encurtar a história: preciso encontrar uma maneira de acessar a barra de progresso do item / exibição em que cliquei, sabendo que posso clicar em vários itens antes que o primeiro chegue ao Receptor de Transmissão.
EDIT: 4 Ok, então eu fiz isso:
y
,z
eld
estão definidos como0
no começo.
Quando um item está sendo clicado:
// 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 radiodifusão :
// 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 bem, exceto quando um item de um arquivo pequeno está sendo clicado enquanto um arquivo grande está sendo baixado. O arquivo pequeno assume a prioridade e o gerenciador de downloads não segue mais a ordem das tabelas, fazendo com que a roda de carregamento não desapareça.
EDIT: 5
Eu encontrei uma maneira de fazer o que eu queria, veja a minha resposta.
Obrigado pela ajuda.