Android: cómo descargar un archivo del servidor web

en mi aplicación, estoy descargando el archivo kml del servidor web. He configurado el permiso de almacenamiento externo e internet en mi archivo de manifiesto de Android. Soy nuevo en Android, su ayuda es muy apreciada

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); } } } 

Archivo de manifiesto de Android

               

Error de Logcat:

 FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start activity 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(Native Method) 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(Native Method) Caused by: 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 { /** * 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); } } } 

Cuando ejecuto este código en el emulador, el código aún no funciona … el archivo no se descarga.

Usando la tarea Async . (Si no funciona en 4.0, agregue

 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); 

)

llame cuando desee descargar el archivo: new DownloadFileFromURL().execute(file_url);

 public class MainActivity extends Activity { // Progress Dialog private ProgressDialog pDialog; public static final int progress_bar_type = 0; // File url to download private static String file_url = "http://www.qwikisoft.com/demo/ashade/20001.kml"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new DownloadFileFromURL().execute(file_url); } /** * Showing Dialog * */ @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; } } /** * Background Async Task to download file * */ class DownloadFileFromURL extends AsyncTask { /** * 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() + "/2011.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); } } } 

Es una mala práctica realizar operaciones de red en el hilo principal, razón por la cual está viendo la NetworkOnMainThreadException . La política lo previene. Si realmente debe hacerlo para probar, coloque lo siguiente en su OnCreate:

  StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); 

Recuerde que esta es una práctica muy mala para hacer esto, y idealmente debería mover su código de red a AsyncTask o a Thread .

Mr.Iam4fun tu código responde aquí … Usarás hilo …

  findViewById(R.id.download).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { public void run() { DownloadFiles(); } }).start(); 

Y entonces..

  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); } } } 

Claro, estará funcionando …

Versión simple de kotlin

 fun download(link: String, path: String) { val input = URL(link).openStream() val output = FileOutputStream(File(path)) input.use { _ -> output.use { _ -> input.copyTo(output) } } } 

Yo recomendaría usar Android DownloadManager

 DownloadManager downloadmanager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); Uri uri = Uri.parse("http://www.example.com/myfile.mp3"); DownloadManager.Request request = new DownloadManager.Request(uri); request.setTitle("My File"); request.setDescription("Downloading"); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setVisibleInDownloadsUi(false); request.setDestinationUri(Uri.parse("file://" + folderName + "/myfile.mp3")); downloadmanager.enqueue(request); 

Ejecuta estos códigos en thread o AsyncTask. Para evitar llamadas duplicadas de la misma _url (una vez para getContentLength (), una vez de openStream ()), use IOUtils.toByteArray de Apache.

 void downloadFile(String _url, String _name) { try { URL u = new URL(_url); DataInputStream stream = new DataInputStream(u.openStream()); byte[] buffer = IOUtils.toByteArray(stream); FileOutputStream fos = mContext.openFileOutput(_name, Context.MODE_PRIVATE); fos.write(buffer); fos.flush(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } } 

Además de utilizar AsyncTask, puede poner la operación en ejecutable

 Runnable r=new Runnable() { public void run() { ///-------network operation code } }; //--------call r in this way-- Thread t=new Thread(r);`enter code here` t.start(); Also put the UI work in a haldler..such as updating a textview etc.. 

Comenzando desde el nivel 11 de api o desde Honeycomb, está prohibido realizar operaciones de red en el hilo principal. Use thread o asynctask. Para obtener más información, visite https://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

usa AsyncTask y

ponga su código de archivo de descarga en doinbackground de él ..

Android ya no permite realizar tareas pesadas en el hilo principal para evitar el error ANR (Aplicación no responde)

Debería usar una AsyncTask (u otra forma de realizar una operación de red en segundo plano).

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //create and execute the download task MyAsyncTask async = new MyAsyncTask(); async.execute(); } private class MyAsyncTask extends AsyncTask{ //execute on background (out of the UI thread) protected Long doInBackground(URL... urls) { DownloadFiles(); } } 

Más información sobre AsyncTask en la documentación de Android

Espero eso ayude.