Il existe de nombreuses façons de télécharger des fichiers. Vous trouverez ci-dessous les méthodes les plus courantes ; c'est à vous de décider quelle méthode est la meilleure pour votre application.
1. Utilisez AsyncTask
et afficher la progression du téléchargement dans une boîte de dialogue
Cette méthode vous permettra d'exécuter certains processus en arrière-plan et de mettre à jour l'interface utilisateur en même temps (dans ce cas, nous mettrons à jour une barre de progression).
Importations :
import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
Voici un exemple de code :
// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;
// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);
// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");
mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true); //cancel the task
}
});
El AsyncTask
ressemblera à ceci :
// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {
private Context context;
private PowerManager.WakeLock mWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
@Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK, so we don't mistakenly save error report
// instead of the file
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
// this will be useful to display download percentage
// might be -1: server did not report the length
int fileLength = connection.getContentLength();
// download the file
input = connection.getInputStream();
output = new FileOutputStream("/sdcard/file_name.extension");
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
return null;
}
total += count;
// publishing the progress....
if (fileLength > 0) // only if total length is known
publishProgress((int) (total * 100 / fileLength));
output.write(data, 0, count);
}
} catch (Exception e) {
return e.toString();
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return null;
}
La méthode ci-dessus ( doInBackground
) s'exécute toujours sur un fil d'arrière-plan. Vous ne devriez pas y effectuer de tâches d'interface utilisateur. D'autre part, le onProgressUpdate
y onPreExecute
s'exécutent sur le thread de l'interface utilisateur, ce qui permet de modifier la barre de progression :
@Override
protected void onPreExecute() {
super.onPreExecute();
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
mProgressDialog.show();
}
@Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
// if we get here, length is known, now set indeterminate to false
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgress(progress[0]);
}
@Override
protected void onPostExecute(String result) {
mWakeLock.release();
mProgressDialog.dismiss();
if (result != null)
Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
else
Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
}
Pour que cela fonctionne, vous avez besoin de la permission WAKE_LOCK.
<uses-permission android:name="android.permission.WAKE_LOCK" />
2. Télécharger à partir de Service
La grande question ici est : comment mettre à jour mon activité à partir d'un service ? . Dans l'exemple suivant, nous allons utiliser deux classes que vous ne connaissez peut-être pas : ResultReceiver
y IntentService
. ResultReceiver
est celui qui nous permettra de mettre à jour notre fil de discussion à partir d'un service ; IntentService
est une sous-classe de Service
qui génère un thread pour effectuer le travail de fond à partir de là (vous devez savoir qu'un Service
s'exécute en fait dans le même thread de votre application ; lorsque vous étendez Service
vous devez manuellement créer de nouveaux threads pour exécuter les opérations de blocage du CPU).
Le service de téléchargement peut ressembler à ceci :
public class DownloadService extends IntentService {
public static final int UPDATE_PROGRESS = 8344;
public DownloadService() {
super("DownloadService");
}
@Override
protected void onHandleIntent(Intent intent) {
String urlToDownload = intent.getStringExtra("url");
ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
try {
//create url and connect
URL url = new URL(urlToDownload);
URLConnection connection = url.openConnection();
connection.connect();
// this will be useful so that you can show a typical 0-100% progress bar
int fileLength = connection.getContentLength();
// download the file
InputStream input = new BufferedInputStream(connection.getInputStream());
String path = "/sdcard/BarcodeScanner-debug.apk" ;
OutputStream output = new FileOutputStream(path);
byte data[] = new byte[1024];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
Bundle resultData = new Bundle();
resultData.putInt("progress" ,(int) (total * 100 / fileLength));
receiver.send(UPDATE_PROGRESS, resultData);
output.write(data, 0, count);
}
// close streams
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
Bundle resultData = new Bundle();
resultData.putInt("progress" ,100);
receiver.send(UPDATE_PROGRESS, resultData);
}
}
Ajoutez le service à votre manifeste :
<service android:name=".DownloadService"/>
Et l'activité ressemblera à ceci :
// initialize the progress dialog like in the first example
// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);
Voici où étaient ResultReceiver
vient jouer :
private class DownloadReceiver extends ResultReceiver{
public DownloadReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode == DownloadService.UPDATE_PROGRESS) {
int progress = resultData.getInt("progress"); //get the progress
dialog.setProgress(progress);
if (progress == 100) {
dialog.dismiss();
}
}
}
}
2.1 Utiliser la bibliothèque de Groundy
Groundy est une bibliothèque qui vous aide à exécuter des morceaux de code dans un service d'arrière-plan. ResultReceiver
concept présenté ci-dessus. Cette bibliothèque est déprécié en ce moment. C'est ainsi que le ensemble du site Le code serait le suivant :
L'activité où vous montrez le dialogue...
public class MainActivity extends Activity {
private ProgressDialog mProgressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
Groundy.create(DownloadExample.this, DownloadTask.class)
.receiver(mReceiver)
.params(extras)
.queue();
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
});
}
private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
switch (resultCode) {
case Groundy.STATUS_PROGRESS:
mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
break;
case Groundy.STATUS_FINISHED:
Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
mProgressDialog.dismiss();
break;
case Groundy.STATUS_ERROR:
Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
mProgressDialog.dismiss();
break;
}
}
};
}
A GroundyTask
utilisée par Groundy pour télécharger le fichier et montrer la progression :
public class DownloadTask extends GroundyTask {
public static final String PARAM_URL = "com.groundy.sample.param.url";
@Override
protected boolean doInBackground() {
try {
String url = getParameters().getString(PARAM_URL);
File dest = new File(getContext().getFilesDir(), new File(url).getName());
DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
return true;
} catch (Exception pokemon) {
return false;
}
}
}
Et ajoutez ceci au manifeste :
<service android:name="com.codeslap.groundy.GroundyService"/>
Ça ne pourrait pas être plus facile, je pense. Il suffit de prendre le dernier bocal à partir de Github et vous êtes prêt à partir. Gardez à l'esprit que Groundy L'objectif principal de l'application est d'appeler des apis REST externes dans un service d'arrière-plan et d'afficher facilement les résultats sur l'interface utilisateur. Si vous faites quelque chose comme ça dans votre application, cela peut être très utile.
3. Utilisez DownloadManager
classe ( GingerBread
et plus récents seulement)
GingerBread a apporté une nouvelle fonctionnalité, DownloadManager
qui vous permet de télécharger facilement des fichiers et de déléguer au système le travail difficile de gestion des threads, des flux, etc.
Voyons d'abord une méthode utilitaire :
/**
* @param context used to check the device version and DownloadManager information
* @return true if the download manager is available
*/
public static boolean isDownloadManagerAvailable(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
return true;
}
return false;
}
Le nom de la méthode explique tout. Une fois que vous êtes sûr DownloadManager
est disponible, vous pouvez faire quelque chose comme ceci :
String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");
// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);
La progression du téléchargement s'affiche dans la barre de notification.
Dernières réflexions
Les première et deuxième méthodes ne sont que la partie émergée de l'iceberg. Il y a beaucoup de choses que vous devez garder à l'esprit si vous voulez que votre application soit robuste. En voici une brève liste :
- Vous devez vérifier si l'utilisateur dispose d'une connexion Internet.
- Assurez-vous que vous avez les bonnes permissions (
INTERNET
y WRITE_EXTERNAL_STORAGE
) ; également ACCESS_NETWORK_STATE
si vous voulez vérifier la disponibilité de l'internet.
- Assurez-vous que le répertoire dans lequel vous allez télécharger les fichiers existe et qu'il a les droits d'écriture.
- Si le téléchargement est trop important, vous pouvez mettre en place un moyen de reprendre le téléchargement si les tentatives précédentes ont échoué.
- Les utilisateurs vous seront reconnaissants si vous leur permettez d'interrompre le téléchargement.
À moins que vous n'ayez besoin d'un contrôle détaillé du processus de téléchargement, envisagez d'utiliser l'option DownloadManager
(3) parce qu'il gère déjà la plupart des éléments énumérés ci-dessus.
Mais considérez également que vos besoins peuvent changer. Par exemple, DownloadManager
ne fait pas de mise en cache des réponses . Il téléchargera aveuglément le même gros fichier plusieurs fois. Il n'y a pas de moyen facile de le réparer après coup. Où si vous commencez avec une base HttpURLConnection
(1, 2), il suffit alors d'ajouter un HttpResponseCache
. L'effort initial d'apprentissage des outils standard de base peut donc être un bon investissement.
Cette classe a été supprimée au niveau 26 de l'API. ProgressDialog est une boîte de dialogue modale qui empêche l'utilisateur d'interagir avec l'application. Au lieu d'utiliser cette classe, cette classe, vous devriez utiliser un indicateur de progression comme la ProgressBar, qui peut être intégré à l'interface utilisateur de votre application. Alternativement, vous pouvez utiliser une notification pour informer l'utilisateur de la progression de la tâche. Pour plus de détails Lien
2 votes
J'espère que le lien ci-dessous pourra vous aider... androidhive.info/2012/04/
1 votes
Pour une solution rapide voir cette réponse
0 votes
stackoverflow.com/a/43069239/3879214 vérifier cette réponse