Tutorial e exemplos do Android DownloadManager
Nesta sessão vamos explorar a classe android.app.DownloadManager
, como usá-la e por que é importante. Veremos questões como os tipos de downloads que você pode fazer com a classe DownloadManager
, como fazer as requisições reais, como mostrar o progresso na barra de status via notificação, abrir arquivo baixado e até remover.
O que é o Gerenciador de Downloads?
_O MARKDOWN_HASH725ed1ec7cb22cb0a4b38d3dd7c624c7MARKDOWNHASH
é um serviço de sistema que podemos usar para lidar com downloads de longa duração.
Por que baixar?
Não subestime a necessidade de downloads e o quão complexo pode ser. O estado da largura de banda na era atual implica que ainda não somos capazes, pelo menos em muitas partes do mundo, de obter os arquivos que precisamos sob demanda a qualquer momento. Os usuários não deixam a internet ligada o tempo todo, pois isso custa dinheiro e drena a bateria do dispositivo.
Portanto, ser capaz de baixar arquivos e armazená-los localmente é importante. Mas esta não é uma tarefa fácil de implementar corretamente. Especialmente fazê-lo corretamente e com eficiência. No entanto, é uma daquelas tarefas que podem ser absolutamente compartilhadas entre aplicativos. Na maioria das vezes, não há necessidade real de reinventar a roda ao fazer downloads http. Faz sentido ter uma classe simples de usar que possa fazer isso com eficiência e informar nosso aplicativo quando a tarefa estiver concluída.
Ser capaz de baixar dados é uma maneira poderosa de enriquecer nossos aplicativos, pois podemos obter arquivos da Internet que nosso aplicativo pode usar. Se o usuário remover o arquivo, podemos baixá-lo novamente.
Perguntas comuns
Aqui estão algumas das perguntas para nos permitir entender a classe DownloadManager
.
Quais tipos de downloads são tratados pelo DownloadManager
Normalmente, existem vários protocolos para comunicação entre dispositivos. E certamente baixar um arquivo é apenas um formulário ou comunicação entre pelo menos dois dispositivos. Um dispositivo fornecendo um arquivo enquanto outro o recebe. Cuidado, o DownloadManager
é usado para lidar apenas com downloads HTTP
.
DownloadManager
é especialmente útil se seus downloads forem de longa duração.
Onde ocorrem os downloads?
Onde em relação a threads. Bem, os downloads definitivamente ocorrerão em segundo plano.
Por que usar o DownloadManager?
Bem, quais são suas vantagens? Pois temos vários. Por exemplo
- Como dissemos, os downloads ocorrem em segundo plano. Na verdade, em segundo plano em um aplicativo do sistema. Isso significa que nosso aplicativo não precisa lidar com os downloads manualmente em nosso encadeamento principal, portanto, nossa interface do usuário é sempre responsiva. Este fato é bastante importante. O download de dados é uma das tarefas que os gadgets pessoais mais consomem tempo e recursos. No entanto, é uma daquelas tarefas que realmente tornam os dispositivos tão poderosos quanto são. Então nós temos que fazê-los. Mas temos que fazê-los em um thread em segundo plano e o
DownloadManager
definitivamente obedece a isso. - Em segundo lugar, as interações HTTP são abstraídas de nós. Não precisamos nos preocupar com vários códigos e mensagens HTTP e possíveis falhas. Na verdade, até mesmo as tentativas são feitas em nosso nome. No entanto, essas novas tentativas podem ser mantidas por meio de alterações no estado de conectividade e reinicializações do sistema. O progresso pode ser mostrado para nós à medida que o download ocorre, tornando-o muito fácil de usar.
Instruções rápidas e trechos do DownloadManager
1. Como baixar vídeos usando a classe DownloadManager
Queremos baixar vídeos usando a classe DownloadManager no android. Queremos dar-lhes nomes apropriados e armazená-los em armazenamento externo.
public void downloadvideo(String videoURL)
{
if(videoURL.contains(".mp4"))
{
File directory = new File(Environment.getExternalStorageDirectory()+File.separator+"My Videos");
directory.mkdirs();
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(videoURL));
int Number=pref.getFileName();
request.allowScanningByMediaScanner();
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
File root = new File(Environment.getExternalStorageDirectory() + File.separator+"Facebook Videos");
Uri path = Uri.withAppendedPath(Uri.fromFile(root), "Video-"+Number+".mp4");
request.setDestinationUri(path);
DownloadManager dm = (DownloadManager)getActivity().getSystemService(getActivity().DOWNLOAD_SERVICE);
if(downloadlist.contains(videoURL))
{
Toast.makeText(getActivity().getApplicationContext(),"The Video is Already Downloading",Toast.LENGTH_LONG).show();
}
else
{
downloadlist.add(videoURL);
dm.enqueue(request);
Toast.makeText(getActivity().getApplicationContext(),"Downloading Video-"+Number+".mp4",Toast.LENGTH_LONG).show();
Number++;
pref.setFileName(Number);
}
}
}
Primeiro, passamos o URL do vídeo como parâmetro. Digamos que queremos baixar apenas arquivos mp4, então fornecemos uma verificação booleana simples para verificar se ele contém
mp4. Talvez você possa usar endsWith()
se quiser em vez de contains()
.
Exemplos de gerenciadores de download
Vejamos alguns exemplos do DownloadManager
.
Exemplo 1. Baixar arquivo, ver todos os downloads, excluir download
Neste exemplo completo queremos ver como baixar um arquivo da internet usando a classe downloadManager. Em seguida, podemos abrir o donwload clicando na notificação na barra do sistema ou internamente em nosso aplicativo. Além disso, podemos excluir o arquivo, visualizar todos os downloads etc.
Vídeo tutorial
Aqui temos um tutorial em vídeo para este exemplo.
Demonstração
Aqui está a demonstração do aplicativo.
Visão geral do aplicativo
- O usuário clica no botão de download.
- O download é iniciado.
- Enquanto isso, o progresso é mostrado na barra de status como uma notificação. A notificação também inclui o título e a descrição do download.
- O usuário é notificado através do texto da barra de status do sistema quando o download é concluído.
- Quando o usuário clica na notificação, o arquivo é aberto. Se não for encontrado, uma mensagem de brinde será exibida.
- Quando o usuário clica no botão
View All
, a visualização de todos os downloads é mostrada. Você pode ter alguns outros downloads enfileirados lá, alguns não do seu aplicativo. - Quando o usuário clica no botão 'Excluir', nosso download, seja parcial ou completo, é excluído.
(uma). MainActivity.java
MainActivity
como você pode imaginar é a nossa atividade de lançador. ele irá derivar do AppCompatActivity
. É aqui que escrevemos todo o nosso código. Mas primeiro começamos fazendo várias importações. Esses incluem:
DownloadManager
- A classe responsável por nos permitir usar o gerenciador de downloads do sistema.- Intent - Classe responsável por nos permitir abrir a visualização do gerenciador de downloads do sistema.
- Uri - Permite analisar um URL de string em um Uri do qual nosso arquivo pode ser baixado.
- Ambiente - Permite especificar o diretório público onde nosso arquivo baixado será armazenado.
- Toast - Permite mostrar mensagens rápidas.
Como fazer
Vejamos vários howTos.
(uma). Como inicializar o DownloadManager
Como um serviço do sistema, o DownloadManager
não é instanciado diretamente. Em vez disso, vamos inicializá-lo usando o método getSystemService()
e converter o objeto resultante na classe DownloadManager
.
private void initializeDownloadManager() {
downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
}
(b). Como criar uma solicitação de download
Dentro da classe DownloadManager há uma classe interna chamada de classe Request
. Podemos usar essa classe para definir nossa solicitação HTTP. Nós fazemos isso convenientemente através do padrão do construtor.
DownloadManager.Request request=new DownloadManager.Request(Uri.parse("https://raw.githubusercontent.com/Oclemy/SampleJSON/master/spacecrafts/voyager.jpg"));
request.setTitle("Voyager")
.setDescription("File is downloading...")
.setDestinationInExternalFilesDir(this,
Environment.DIRECTORY_DOWNLOADS,fileName)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
Claramente você pode ver que passamos o Uri
em nosso construtor Request
. Em seguida, defina o título, descrição, destino e visibilidade da notificação.
(c). Como enfileirar um download
Enfileirar um download significa adicioná-lo à fila de download do gerenciador de download. Em seguida, a fila será processada automaticamente pelo sistema. Você enfileira um download usando o método enqueue()
.
downLoadId=downloadManager.enqueue(request);
Isso nos retornará um ID de download.
(d). Como remover/excluir arquivo baixado
Bem, você pode remover um arquivo baixado do gerenciador de downloads usando o método remove()
da classe DownloadManager
. Você passa o id de download.
private void deleteDownloadedFile(){
downloadManager.remove(downLoadId);
}
Aqui está o código fonte completo.
package info.camposha.mrdownloadmanager;
import android.app.DownloadManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import java.io.FileNotFoundException;
public class MainActivity extends AppCompatActivity {
private DownloadManager downloadManager;
private String fileName=null;
private long downLoadId;
/**
* Initialize download manager
*/
private void initializeDownloadManager() {
downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
fileName="Voyager";
}
/**
* Set the title and desc of this download, to be displayed in notifications.
*/
private void downloadFile(){
DownloadManager.Request request=new DownloadManager.Request(Uri.parse("https://raw.githubusercontent.com/Oclemy/SampleJSON/master/spacecrafts/voyager.jpg"));
request.setTitle("Voyager")
.setDescription("File is downloading...")
.setDestinationInExternalFilesDir(this,
Environment.DIRECTORY_DOWNLOADS,fileName)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//Enqueue the download.The download will start automatically once the download manager is ready
// to execute it and connectivity is available.
downLoadId=downloadManager.enqueue(request);
}
/**
* Cancel downloads and remove them from the download manager.
* If there is a downloaded file, partial or complete, it is deleted.
*/
private void deleteDownloadedFile(){
downloadManager.remove(downLoadId);
}
private void openOurDownload(){
//we can open download here
}
/**
* View all downloads in the downloadmanager
*/
private void viewAllDownloads(){
Intent intent=new Intent();
intent.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(intent);
}
/**
* Handle button clicks
* @param view
*/
public void clickView(View view){
switch (view.getId()){
case R.id.downloadBtn:
downloadFile();
break;
case R.id.openDownloadBtn:
openOurDownload();
break;
case R.id.viewDownloadsBtn:
viewAllDownloads();
break;
case R.id.deleteBtn:
deleteDownloadedFile();
break;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeDownloadManager();
}
}
(b). atividade_main.xml
Precisamos de um layout para nossa MainActivity
. Aqui está o código.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android_layout_width="match_parent"
android_layout_height="match_parent"
android_orientation="vertical"
android_background="#009688"
tools_context=".MainActivity">
<TextView
android_id="@+id/headerTxt"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_text="DownloadManager Example"
android_textAlignment="center"
android_fontFamily="casual"
android_textStyle="bold"
android_textAppearance="@style/TextAppearance.AppCompat.Large"
android_textColor="@color/white" />
<ImageView
android_layout_width="match_parent"
android_layout_height="300dp"
android_layout_centerHorizontal="true"
android_src="@drawable/logo"
android_contentDescription="@string/app_name"/>
<LinearLayout
android_id="@+id/button_zone"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_orientation="horizontal"
android_layout_centerInParent="true">
<Button
android_id="@+id/downloadBtn"
style="?android:attr/button"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_layout_weight="1"
android_onClick="clickView"
android_text="Download" />
<Button
android_id="@+id/viewDownloadsBtn"
style="?android:attr/button"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_layout_weight="1"
android_onClick="clickView"
android_text="View All" />
</LinearLayout>
<LinearLayout
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_orientation="horizontal"
android_layout_centerInParent="true">
<Button
android_id="@+id/openDownloadBtn"
style="?android:attr/button"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_layout_weight="1"
android_onClick="clickView"
android_text="Open" />
<Button
android_id="@+id/deleteBtn"
style="?android:attr/button"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_layout_weight="1"
android_onClick="clickView"
android_text="Delete" />
</LinearLayout>
</LinearLayout>
(c). AndroidManifest.xml
Em nosso AndroidManifest, precisamos adicionar permissões para conectividade com a Internet, bem como para gravar em armazenamento externo. Isso ocorre porque baixamos nossa imagem da Internet e gravamos em nosso armazenamento externo.
Aqui está meu arquivo AndroidManifest.xml
completo:
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="info.camposha.mrdownloadmanager">
<uses-permission android_name="android.permission.INTERNET"/>
<uses-permission android_name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android_allowBackup="true"
android_icon="@mipmap/ic_launcher"
android_label="@string/app_name"
android_roundIcon="@mipmap/ic_launcher_round"
android_supportsRtl="true"
android_theme="@style/AppTheme">
<activity android_name=".MainActivity">
<intent-filter>
<action android_name="android.intent.action.MAIN" />
<category android_name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Download
Aqui estão os recursos de referência:
Não. | Localização | Ligação |
---|---|---|
1. | GitHub | Download direto |
2. | GitHub | Navegar |
3. | YouTube | Tutorial em vídeo |
4. | YouTube | ProgrammingWizards TV Channel |
Exemplo 2: Exemplo simples do DownloadManager de Kotlin Android
Um exemplo simples de gerenciador de download Kotlin de código aberto adequado para iniciantes absolutos.
Etapa 1: criar projeto
Comece criando um projeto AndroidStudio vazio.
Etapa 2: dependências
Nenhuma biblioteca especial de terceiros é necessária para este projeto.
Etapa 3: Layout do projeto
Projete seu layout MainActivity adicionando uma visualização de texto em um ConstraintLayout conforme mostrado abaixo:
atividade_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Etapa 4: escrever código
Comece adicionando importações:
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.opengl.Visibility
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
Crie MainActivity
estendendo AppCompatActivity
:
class MainActivity : AppCompatActivity() {
Defina um ID de download:
var downloadid: Long = 0
Substituir o retorno de chamada onCreate()
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Crie um BroadcastReceiver anônimo e dentro dele substitua o onReceive()
da seguinte forma:
val new = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadid) Log.d("DOWNLOAD", "DONE")
}
}
Crie um Uri de download:
val uri = Uri.parse("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
Inicialize um DownloadRequest:
val request = DownloadManager.Request(uri).setDescription("DummyFile").setTitle("Dummy").setAllowedOverMetered(true).setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
Enfileirar o download:
val location = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadid = location.enqueue(request)
Registre o BroadcastReceiver:
registerReceiver(new, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
Aqui está o código completo:
MainActivity.kt
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.opengl.Visibility
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
class MainActivity : AppCompatActivity() {
var downloadid: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val new = object: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadid) Log.d("DOWNLOAD", "DONE")
}
}
val uri = Uri.parse("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
val request = DownloadManager.Request(uri).setDescription("DummyFile").setTitle("Dummy").setAllowedOverMetered(true).setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
val location = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadid = location.enqueue(request)
registerReceiver(new, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
}
}
Etapa 5: adicionar permissões
No seu AndroidManifest
adicione as seguintes permissões:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
Correr
Copie o código ou baixe-o no link abaixo, construa e execute.
Referência
Seguem os links de referência:
Exemplo 3: Kotlin Android - Download dinâmico
Neste exemplo você aprende como baixar de qualquer link. O link é fornecido em tempo de execução por meio de um EditText.
Etapa 1: criar projeto
Comece criando um projeto AndroidStudio vazio.
Etapa 2: dependências
Nenhuma dependência de terceiros é necessária para este projeto.
Etapa 3: Layout do projeto
Adicione um EditText e Button no layout da sua atividade principal:
atividade_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilLink"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:hint="Введите ссылку"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etLink"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/btnLoad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="load"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilLink" />
</androidx.constraintlayout.widget.ConstraintLayout>
Etapa 4: escrever código
Comece adicionando importações ao seu MainActivity.kt
da seguinte forma:
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.view.Gravity
import android.widget.PopupMenu
import android.widget.Toast
import com.google.android.material.textfield.TextInputEditText
Crie a atividade:
class MainActivity : AppCompatActivity() {
Defina campos de instância:
private var binding: ActivityMainBinding? = null
private var dm: DownloadManager? = null
Crie uma classe BroadcastReceiver anônima e implemente o método onReceive()
da seguinte forma:
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
Toast.makeText(context, "Download Completed", Toast.LENGTH_SHORT).show()
}
}
}
Configurar manipuladores de eventos:
private fun setupListeners() {
binding?.btnLoad?.setOnLongClickListener {
val popup = PopupMenu(this, it)
popup.inflate(R.menu.popup)
popup.show()
download()
false
}
}
Aqui está a função que baixa o item:
private fun download() {
dm?.enqueue(
DownloadManager.Request(Uri.parse(LINK_VIDEO))
.setAllowedNetworkTypes(
DownloadManager.Request.NETWORK_MOBILE or
DownloadManager.Request.NETWORK_WIFI
)
.setTitle("Download File.mp4")
.setDescription("This is very important file")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
// .setDestinationInExternalFilesDir(
// applicationContext , Environment.DIRECTORY_DOWNLOADS, "managerDownload24.mp4"
// )
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"managerDownload24"
)
)
}
Cancele o registro do BroadcastReceiver no onCreate()
:
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
}
Aqui está o código completo:
MainActivity.kt
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.view.Gravity
import android.widget.PopupMenu
import android.widget.Toast
import com.google.android.material.textfield.TextInputEditText
import ru.trinitydigital.downloadmanager.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
private var dm: DownloadManager? = null
private val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
Toast.makeText(context, "Download Completed", Toast.LENGTH_SHORT).show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding?.root)
registerReceiver(broadcastReceiver, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE))
dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
setupListeners()
}
private fun setupListeners() {
binding?.btnLoad?.setOnLongClickListener {
val popup = PopupMenu(this, it)
popup.inflate(R.menu.popup)
popup.show()
download()
false
}
}
private fun download() {
dm?.enqueue(
DownloadManager.Request(Uri.parse(LINK_VIDEO))
.setAllowedNetworkTypes(
DownloadManager.Request.NETWORK_MOBILE or
DownloadManager.Request.NETWORK_WIFI
)
.setTitle("Download File.mp4")
.setDescription("This is very important file")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
// .setDestinationInExternalFilesDir(
// applicationContext , Environment.DIRECTORY_DOWNLOADS, "managerDownload24.mp4"
// )
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"managerDownload24"
)
)
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(broadcastReceiver)
}
companion object {
private const val LINK_VIDEO = "https://images.unsplash.com/photo-1569974507005-6dc61f97fb5c?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MXx8anBnfGVufDB8fDB8&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60"
}
}
Manifesto Android
No AndroidManifest.xml
adicione as seguintes permissões:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Correr
Copie o código ou baixe-o no link abaixo, construa e execute.
Referência
Seguem os links de referência:
Número | Ligação |
---|---|
1. | Download Exemplo |
2. | Siga autor do código |
Exemplo 4: Kotlin DownloadManager com permissões de tempo de execução e corrotinas
Aqui está mais um exemplo de DownloadManager escrito em Kotlin. Isso utiliza Kotlin Coroutines. Também envolve a verificação das permissões necessárias em tempo de execução antes do download.
Etapa 1: criar projeto
Comece criando um projeto AndroidStudio
vazio.
Etapa 2: dependências
Nenhuma dependência de terceiros é usada.
Etapa 3: Layout do projeto
Crie um layout simples com um botão e uma visualização de texto:
atividade_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="12dp"
android:textColor="@color/black"
android:textSize="25sp" />
<Button
android:id="@+id/download_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="12dp"
android:text="DOWNLOAD PDF"
android:textColor="@android:color/white" />
</LinearLayout>
</RelativeLayout>
Etapa 4: escrever código
Comece adicionando importações:
import android.Manifest
import android.annotation.TargetApi
import android.app.DownloadManager
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
Estenda a AppCompatActivity
:`
class MainActivity : AppCompatActivity() {
Em seguida, defina um URL de download como um campo de instância:
private var imageUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
Substitua o onCreate()
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Quando o botão de download é clicado, antes de iniciar o download, verificamos a permissão:
download_btn.setOnClickListener {
// After API 23 (Marshmallow) and lower Android 10 you need to ask for permission first before save an image
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
askPermissions()
} else {
downloadImage(imageUrl)
}
}
Se concedido, iniciamos o download.
Aqui está a função para iniciar o download da imagem:
private fun downloadImage(url: String) {
val downloadManager = this.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadUri = Uri.parse(url)
val request = DownloadManager.Request(downloadUri).apply {
setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(url.substring(url.lastIndexOf("/") + 1))
.setDescription("abc")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
url.substring(url.lastIndexOf("/") + 1)
)
}
//use when just to download the file with getting status
//downloadManager.enqueue(request)
val downloadId = downloadManager.enqueue(request)
val query = DownloadManager.Query().setFilterById(downloadId)
lifecycleScope.launchWhenStarted {
var lastMsg: String = ""
var downloading = true
while (downloading) {
val cursor: Cursor = downloadManager.query(query)
cursor.moveToFirst()
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false
}
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
val msg: String? = statusMessage(url, File(Environment.DIRECTORY_DOWNLOADS), status)
Log.e("DownloadManager", " Status is :$msg")
if (msg != lastMsg) {
withContext(Dispatchers.Main) {
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
text_view.text = msg
//Log.e("DownloadManager", "Status is :$msg")
}
lastMsg = msg ?: ""
}
cursor.close()
}
}
}
Aqui está a função que constrói e retorna o status de Download como uma string que pode ser exibida ao usuário:
private fun statusMessage(url: String, directory: File, status: Int): String? {
var msg = ""
msg = when (status) {
DownloadManager.STATUS_FAILED -> "Download has been failed, please try again"
DownloadManager.STATUS_PAUSED -> "Paused"
DownloadManager.STATUS_PENDING -> "Pending"
DownloadManager.STATUS_RUNNING -> "Downloading..."
DownloadManager.STATUS_SUCCESSFUL -> "PDF downloaded successfully in $directory" + File.separator + url.substring(
url.lastIndexOf("/") + 1
)
else -> "There's nothing to download"
}
return msg
}
A função a seguir permitirá que você solicite as permissões necessárias antes de prosseguir com o download:
@TargetApi(Build.VERSION_CODES.M)
fun askPermissions() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
AlertDialog.Builder(this)
.setTitle("Permission required")
.setMessage("Permission required to save photos from the Web.")
.setPositiveButton("Allow") { dialog, id ->
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
)
finish()
}
.setNegativeButton("Deny") { dialog, id -> dialog.cancel() }
.show()
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
)
// MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
downloadImage(imageUrl)
}
}
Em seguida, processe a solicitação de permissão resultando no seguinte retorno de chamada:
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// permission was granted, yay!
// Download the Image
downloadImage(imageUrl)
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return
}
// Add other 'when' lines to check for other
// permissions this app might request.
else -> {
// Ignore all other requests.
}
}
}
Aqui está o código completo:
MainActivity.kt
import android.Manifest
import android.annotation.TargetApi
import android.app.DownloadManager
import android.content.Context
import android.content.pm.PackageManager
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class MainActivity : AppCompatActivity() {
private var imageUrl = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
//private var imageUrl = "http://10.0.2.2:8087/getFile"
//private var imageUrl = "https://www.orimi.com/pdf-test.pdf"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
download_btn.setOnClickListener {
//http://localhost:8087/getFile
//downloadImage("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
//downloadImage("http://localhost:8087/getFile")
// After API 23 (Marshmallow) and lower Android 10 you need to ask for permission first before save an image
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
askPermissions()
} else {
downloadImage(imageUrl)
}
}
}
private fun downloadImage(url: String) {
//val directory = File(Environment.DIRECTORY_PICTURES)
// if (!directory.exists()) {
// directory.mkdirs()
// }
val downloadManager = this.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadUri = Uri.parse(url)
val request = DownloadManager.Request(downloadUri).apply {
setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
.setAllowedOverRoaming(false)
.setTitle(url.substring(url.lastIndexOf("/") + 1))
.setDescription("abc")
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
url.substring(url.lastIndexOf("/") + 1)
)
}
//use when just to download the file with getting status
//downloadManager.enqueue(request)
val downloadId = downloadManager.enqueue(request)
val query = DownloadManager.Query().setFilterById(downloadId)
lifecycleScope.launchWhenStarted {
var lastMsg: String = ""
var downloading = true
while (downloading) {
val cursor: Cursor = downloadManager.query(query)
cursor.moveToFirst()
if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
downloading = false
}
val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
val msg: String? = statusMessage(url, File(Environment.DIRECTORY_DOWNLOADS), status)
Log.e("DownloadManager", " Status is :$msg")
if (msg != lastMsg) {
withContext(Dispatchers.Main) {
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
text_view.text = msg
//Log.e("DownloadManager", "Status is :$msg")
}
lastMsg = msg ?: ""
}
cursor.close()
}
}
}
private fun statusMessage(url: String, directory: File, status: Int): String? {
var msg = ""
msg = when (status) {
DownloadManager.STATUS_FAILED -> "Download has been failed, please try again"
DownloadManager.STATUS_PAUSED -> "Paused"
DownloadManager.STATUS_PENDING -> "Pending"
DownloadManager.STATUS_RUNNING -> "Downloading..."
DownloadManager.STATUS_SUCCESSFUL -> "PDF downloaded successfully in $directory" + File.separator + url.substring(
url.lastIndexOf("/") + 1
)
else -> "There's nothing to download"
}
return msg
}
@TargetApi(Build.VERSION_CODES.M)
fun askPermissions() {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
AlertDialog.Builder(this)
.setTitle("Permission required")
.setMessage("Permission required to save photos from the Web.")
.setPositiveButton("Allow") { dialog, id ->
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
)
finish()
}
.setNegativeButton("Deny") { dialog, id -> dialog.cancel() }
.show()
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE
)
// MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
downloadImage(imageUrl)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// permission was granted, yay!
// Download the Image
downloadImage(imageUrl)
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return
}
// Add other 'when' lines to check for other
// permissions this app might request.
else -> {
// Ignore all other requests.
}
}
}
companion object {
private const val MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1
}
}
Correr
Copie o código ou baixe-o no link abaixo, construa e execute.
Referência
Seguem os links de referência: