80 votes

Android - Comment télécharger un fichier à partir d'un serveur Web ?

Dans mon application, je télécharge un kml à partir d'un serveur web. J'ai défini les autorisations pour le stockage externe et l'Internet dans mon fichier manifeste Android. Je suis nouveau dans le monde d'Android, votre aide est très appréciée.

MainActivity.java

package com.example.demo;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        DownloadFiles();
    }

    public void DownloadFiles(){
        try {
            URL u = new URL("http://www.qwikisoft.com/demo/ashade/20001.kml");
            InputStream is = u.openStream();
            DataInputStream dis = new DataInputStream(is);

            byte[] buffer = new byte[1024];
            int length;

            FileOutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/" + "data/test.kml"));
            while ((length = dis.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }

        } catch (MalformedURLException mue) {
            Log.e("SYNC getUpdate", "malformed url error", mue);
        } catch (IOException ioe) {
            Log.e("SYNC getUpdate", "io error", ioe);
        } catch (SecurityException se) {
            Log.e("SYNC getUpdate", "security error", se);
        }
    }
}

Fichier manifeste Android

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.demo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.example.demo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Erreur de logcat :

FATAL EXCEPTION : main java.lang.RuntimeException : Impossible de démarrer l'activité ComponentInfo{com.example.demo/com.example.demo.MainActivity} : Android.os.NetworkOnMainThreadException at Android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956) at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981) at Android.app.ActivityThread.access$600(ActivityThread.java:123) at Android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147) at Android.os.Handler.dispatchMessage(Handler.java:99) at Android.os.Looper.loop(Looper.java:137) at Android.app.ActivityThread.main(ActivityThread.java:4424) at java.lang.reflect.Method.invokeNative(Méthode native) at java.lang.reflect.Method.invoke(Method.java:511) at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) at com.Android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at dalvik.system.NativeStart.main(Méthode native) Causé par : Android.os.NetworkOnMainThreadException at Android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099) at java.net.InetAddress.lookupHostByName(InetAddress.java:391) at java.net.InetAddress.getAllByNameImpl(InetAddress.java:242) at java.net.InetAddress.getAllByName(InetAddress.java:220) at libcore.net.http.HttpConnection.(HttpConnection.java:71) at libcore.net.http.HttpConnection.(HttpConnection.java:50) at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:351) at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:86) at libcore.net.http.HttpConnection.connect(HttpConnection.java:128) at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:308) at libcore.net.http.HttpEngine.connect(HttpEngine.java:303) at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282) at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232) at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273) at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:168) at java.net.URL.openStream(URL.java:462) at com.example.demo.MainActivity.DownloadFiles(MainActivity.java:30) at com.example.demo.MainActivity.onCreate(MainActivity.java:24) at Android.app.Activity.performCreate(Activity.java:4465) at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) at Android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)

EDITAR

package com.example.demo;

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;

public class MainActivity extends Activity {

    private ProgressDialog pDialog;
    public static final int progress_bar_type = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new DownloadFileFromURL().execute("http://www.qwikisoft.com/demo/ashade/20001.kml");
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
            case progress_bar_type: // we set this to 0
                pDialog = new ProgressDialog(this);
                pDialog.setMessage("Downloading file. Please wait...");
                pDialog.setIndeterminate(false);
                pDialog.setMax(100);
                pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                pDialog.setCancelable(true);
                pDialog.show();
                return pDialog;
            default:
                return null;
        }
    }

    class DownloadFileFromURL extends AsyncTask<String, String, String> {

        /**
         * Before starting background thread Show Progress Bar Dialog
         **/
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            showDialog(progress_bar_type);
        }

        /**
         * Downloading file in background thread
         **/
        @Override
        protected String doInBackground(String... f_url) {
            int count;
            try {
                URL url = new URL(f_url[0]);
                URLConnection conection = url.openConnection();
                conection.connect();

                // this will be useful so that you can show a tipical 0-100%
                // progress bar
                int lenghtOfFile = conection.getContentLength();

                // download the file
                InputStream input = new BufferedInputStream(url.openStream(),
                        8192);

                // Output stream
                OutputStream output = new FileOutputStream(Environment
                        .getExternalStorageDirectory().toString()
                        + "/data/downloadedfile.kml");

                byte data[] = new byte[1024];

                long total = 0;

                while ((count = input.read(data)) != -1) {
                    total += count;
                    // publishing the progress....
                    // After this onProgressUpdate will be called
                    publishProgress("" + (int) ((total * 100) / lenghtOfFile));

                    // writing data to file
                    output.write(data, 0, count);
                }

                // flushing output
                output.flush();

                // closing streams
                output.close();
                input.close();
            } catch (Exception e) {
                Log.e("Error: ", e.getMessage());
            }

            return null;
        }

        /**
         * Updating progress bar
         **/
        protected void onProgressUpdate(String... progress) {
            // setting progress percentage
            pDialog.setProgress(Integer.parseInt(progress[0]));
        }

        /**
         * After completing background task Dismiss the progress dialog
         **/
        @Override
        protected void onPostExecute(String file_url) {
            // dismiss the dialog after the file was downloaded
            dismissDialog(progress_bar_type);
        }
    }
}

Lorsque j'exécute ce code dans l'émulateur, le code ne fonctionne toujours pas - le fichier n'est pas téléchargé.

0voto

CodeInsideCoffee Points 760

Voici le code qui vous aidera à télécharger un fichier depuis le serveur et vous pourrez voir la progression du téléchargement sur votre barre d'état.

Voir la fonctionnalité dans l'image ci-dessous de mon code :

enter image description here enter image description here

ÉTAPE - 1 : Créer sur Télécharger un fichier à partir de l'URL.java pour télécharger le contenu du fichier à partir du serveur. Ici, je crée une tâche asynchrone pour télécharger le fichier.

public class DownloadFileFromURL extends AsyncTask<String, Integer, String> {

private NotificationManager mNotifyManager;
private NotificationCompat.Builder build;
private File fileurl;
int id = 123;
OutputStream output;
private Context context;
private String selectedDate;
private String ts = "";

public DownloadFileFromURL(Context context, String selectedDate) {
    this.context = context;
    this.selectedDate = selectedDate;

}

protected void onPreExecute() {
    super.onPreExecute();

    mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    build = new NotificationCompat.Builder(context);
    build.setContentTitle("Download")
            .setContentText("Download in progress")
            .setChannelId(id + "")
            .setAutoCancel(false)
            .setDefaults(0)
            .setSmallIcon(R.drawable.ic_menu_download);

    // Since android Oreo notification channel is needed.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel = new NotificationChannel(id + "",
                "Social Media Downloader",
                NotificationManager.IMPORTANCE_HIGH);
        channel.setDescription("no sound");
        channel.setSound(null, null);
        channel.enableLights(false);
        channel.setLightColor(Color.BLUE);
        channel.enableVibration(false);
        mNotifyManager.createNotificationChannel(channel);

    }
    build.setProgress(100, 0, false);
    mNotifyManager.notify(id, build.build());
    String msg = "Download started";
    //CustomToast.showToast(context,msg);
}

@Override
protected String doInBackground(String... f_url) {
    int count;
    ts = selectedDate.split("T")[0];
    try {
        URL url = new URL(f_url[0]);
        URLConnection conection = url.openConnection();
        conection.connect();
        int lenghtOfFile = conection.getContentLength();

        InputStream input = new BufferedInputStream(url.openStream(),
                8192);
        // Output stream
        output = new FileOutputStream(Environment
                .getExternalStorageDirectory().toString()
                + Const.DownloadPath + ts + ".pdf");
        fileurl = new File(Environment.getExternalStorageDirectory()
                + Const.DownloadPath + ts + ".pdf");
        byte[] data = new byte[1024];

        long total = 0;

        while ((count = input.read(data)) != -1) {
            total += count;
            int cur = (int) ((total * 100) / lenghtOfFile);

            publishProgress(Math.min(cur, 100));
            if (Math.min(cur, 100) > 98) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Log.d("Failure", "sleeping failure");
                }
            }
            Log.i("currentProgress", "currentProgress: " + Math.min(cur, 100) + "\n " + cur);

            output.write(data, 0, count);
        }

        output.flush();

        output.close();
        input.close();

    } catch (Exception e) {
        Log.e("Error: ", e.getMessage());
    }

    return null;
}

protected void onProgressUpdate(Integer... progress) {
    build.setProgress(100, progress[0], false);
    mNotifyManager.notify(id, build.build());
    super.onProgressUpdate(progress);
}

@Override
protected void onPostExecute(String file_url) {
    build.setContentText("Download complete");
    build.setProgress(0, 0, false);
    mNotifyManager.notify(id, build.build());
} }

Nota: Si vous voulez un code avec un paquet d'importation, alors Cliquez ici

Maintenant, étape 2 : Vous devez appeler la tâche asynchrone ci-dessus sur votre événement de clic. Par exemple, j'ai mis sur l'icône d'image de pdf. Pour appeler AsyncTask utiliser le code ci-dessous :

 new DownloadFileFromURL(fContext,filename).execute(serverFileUrl);

Nota: Ici, vous pouvez voir nom de fichier variable dans le paramètre du fichier. C'est le nom que j'utilise pour sauvegarder mon fichier téléchargé dans le dispositif local. Actuellement, je télécharge seulement le fichier pdf mais vous pouvez utiliser votre url dans le paramètre file. serverFileUrl paramètre.

0voto

Amin Keshavarzian Points 143

Voici comment je télécharge en utilisant retrofit, enregistre et renvoie un fichier au viewmodel :)

interface FileDownloader { objet compagnon { privé val instance : FileDownloader by lazy {

        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = HttpLoggingInterceptor.Level.HEADERS

        val client = OkHttpClient.Builder()
            .connectTimeout(120, TimeUnit.SECONDS)
            .readTimeout(300, TimeUnit.SECONDS)
            .callTimeout(300, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .build()

        val downloaderApi = Retrofit.Builder()
            .baseUrl("https://exmaple.com")
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build()
            .create(FileDownloader::class.java)

        downloaderApi
    }

    suspend fun downloadAndSaveFile(
        url: String
    ): File {
        val file = getPdfFile()
        val responseBody = try {
            instance.downloadFile(url)
        } catch (e: Exception) {
            throw FileDownloadException(url, e)
        }
        @Suppress("BlockingMethodInNonBlockingContext")
        try {
            FileOutputStream(file).use { outputStream ->
                responseBody.byteStream().use { inputStream ->
                    inputStream.copyTo(outputStream)
                }
            }
        } catch (e: Exception) {
            throw FileDownloadException(url, e)
        }
        return file
    }

}

@GET
@Streaming
suspend fun downloadFile(@Url utl: String): ResponseBody
}

fun getPdfFile(): File {
    File(App.appContext.filesDir, "pdfs").apply { mkdirs() }
    return File(App.appContext.filesDir, "tempPDF.pdf")
}

class FileDownloadException(url: String, e: Exception) : Throwable()

-1voto

Bek Points 1102

A partir du niveau 11 de l'API ou de Honeycomb, il est interdit d'effectuer des opérations réseau sur le thread principal. Utilisez le thread ou l'asynctask. Pour plus d'informations, visitez https://developer.Android.com/reference/Android/os/NetworkOnMainThreadException.html

-1voto

sunny Points 11

Lorsque vous cliquez sur le bouton de téléchargement, vous devez d'abord créer le chemin de stockage local où vous voulez le sauvegarder, nous devrions mettre la fonctionnalité de téléchargement de fichier dans ExecutorService (qui est utilisé au lieu de AsyncTask parce que AsyncTask est déprécié).

// Create bamchik folder if not created yet
val folder = File(context?.getExternalFilesDir(null)?.absoluteFile, "MusicTrack")
val check = folder.mkdirs()
Log.v(mTAG, "check: $check")
var path = context?.getExternalFilesDir(null)?.absolutePath + "/MusicTrack/music." + fileExt
val SDK_INT = Build.VERSION.SDK_INT
if (SDK_INT > 8) {
    val policy: StrictMode.ThreadPolicy = StrictMode.ThreadPolicy.Builder().permitAll().build()
    StrictMode.setThreadPolicy(policy)
    val executor: ExecutorService = Executors.newSingleThreadExecutor()
    val handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            // Length is the total size of file and progress is how much file have been downloaded, now you can show progress according to this
            val (progress, length) = msg.obj as Pair<Long, Long> 
            Log.v(mTAG, "Progress: $progress, Length: $length")
        }

    }

    executor.execute {
        //Background work here
        download(link, path) { progress, length ->
            // handling the result on main thread
            handler.sendMessage(handler.obtainMessage(0, progress to length))
        }
        handler.post {
            //UI Thread work here
        }
    }
}

Fonction de téléchargement de fichiers à partir d'une URL

fun download(link: String, path: String, progress: ((Long, Long) -> Unit)? = null): Long {
    val url = URL(link)
    val connection = url.openConnection()
    connection.connect()
    val length = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) connection.contentLengthLong else connection.contentLength.toLong()
    url.openStream().use { input ->
        FileOutputStream(File(path)).use { output ->
            val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
            var bytesRead = input.read(buffer)
            var bytesCopied = 0L
            while (bytesRead >= 0) {
                output.write(buffer, 0, bytesRead)
                bytesCopied += bytesRead
                progress?.invoke(bytesCopied, length)
                bytesRead = input.read(buffer)
            }

            return bytesCopied
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X