Se você já tentou se aprofundar no universo mobile e tentou realizar algum tipo de download dentro de sua aplicação, com certeza já se deparou com a classe DownloadManager, um serviço dentro do Android que é chamado pela sua aplicação para executar o download.
O gerenciador de download é um serviço de sistema que lida com downloads HTTP de longa duração. Os clientes podem solicitar que um URI seja baixado para um arquivo de destino específico. O gerenciador de download conduzirá o download em segundo plano, cuidando das interações HTTP e tentando novamente os downloads após falhas ou entre alterações de conectividade e reinicializações do sistema.
No entanto, o DownloadManager contem alguns problemas que podem lhe dar algumas dores de cabeça. Quando comecei a utiliza-lo me deparei com bugs que faziam com que meu download nunca começasse até problema de bloqueio de IP já que a rede que meu aplicativo utilizava bloqueava alguns IP’s da Google já que o seu download acaba passando pela rede da Google.
A solução foi buscar alternativas para o Download Manager e logo de cara me deparei com o repositório do Fetch2 que acabou solucionando todos os meus problemas com uma implementação simples e com vários métodos já prontos que com o Download Manager tive que fazer. Abaixo estarei utilizando o exemplo do próprio projeto.
São necessárias as permissões de leitura e escrita no armazenamento e de acesso a internet para o seu aplicativo, então insira no seu AndroidManifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
Para utilizar o Fetch, adicione a implementação no seu build.gradle:
implementation "com.tonyodev.fetch2:fetch2:3.0.12"
// OU
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.6"
// PARA ANDROIDX
E agora vamos ao código!
Comece declarando a variável onde guardaremos a instancia do Fetch:
public class TestActivity extends AppCompatActivity {
private Fetch fetch;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
Em seguida vamos definir as configurações do Fetch e inseri-los na instancia
public class TestActivity extends AppCompatActivity {
private Fetch fetch;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Builder para criação de configurações
FetchConfiguration fetchConfiguration = new FetchConfiguration.Builder(this)
.setDownloadConcurrentLimit(3) // Setamos o limite de downloads paralelos para 3
.build();
// Devemos utilizar o getInstance e passar as configurações desejados para salvar na variável Fetch
fetch = Fetch.Impl.getInstance(fetchConfiguration);
String origem = "http:www.example.com/test.txt";
String destino = "/downloads/test.txt";
// Por fim montamos a requisição instanciando um Request
final Request request = new Request(origem, destino);
request.setPriority(Priority.HIGH); // Setamos a prioridade
request.setNetworkType(NetworkType.ALL); // Limitações de rede (WI-FI ou Dados Moveis)
request.addHeader("clientKey", "SD78DF93_3947&MVNGHE1WONG"); // Exemplo de cabeçalho
// Adicionado o request na fila de downloads
fetch.enqueue(request, updatedRequest -> {
// Callback para caso o download tenha sido inserido na fila com sucesso
}, error -> {
// Callback para caso tenha ocorrido algum problema ao inserir na fila
});
}
}
Com apenas esse trecho de código o download já é realizado, porém, temos a possibilidade de adicionar um Listener para acompanhar com mais detalhes o andamento do download. É através do Listener que conseguimos acessar métodos que retornam o tempo aproximado para o fim de download, quantidade de bytes já baixados e etc…
Adicionando o Listener
Dentro do nosso método onCreate criaremos uma classe anônima que será filha da classe FetchListener. Em seguida, teremos que implementar os seguintes métodos e adicionar o fetchListener em nosso objeto fetch.
FetchListener fetchListener = new FetchListener() {
@Override
public void onQueued(@NotNull Download download, boolean waitingOnNetwork) {
if (request.getId() == download.getId()) {
showDownloadInList(download);
}
}
@Override
public void onCompleted(@NotNull Download download) {
}
@Override
public void onError(@NotNull Download download) {
Error error = download.getError();
}
@Override
public void onProgress(@NotNull Download download, long etaInMilliSeconds, long downloadedBytesPerSecond) {
if (request.getId() == download.getId()) {
updateDownload(download, etaInMilliSeconds);
}
int progress = download.getProgress(); // Porcentagem do download
}
@Override
public void onPaused(@NotNull Download download) {
}
@Override
public void onResumed(@NotNull Download download) {
}
@Override
public void onCancelled(@NotNull Download download) {
}
@Override
public void onRemoved(@NotNull Download download) {
}
@Override
public void onDeleted(@NotNull Download download) {
}
};
// Adiciona o listener
fetch.addListener(fetchListener);
// Remove o listener ao concluir o download.
fetch.removeListener(fetchListener);
Por fim, temos a implementação completa do Fetch2 e basta realizar as alterações para que se encaixe no projeto.
E você, conhece outra biblioteca que pode ajudar a resolver um problema parecido? Deixe nos comentários!