Android-如何从网络服务器下载文件

在我的应用程序中,我正在从一个网络服务器下载一个 kml文件。我已经在我的机器人清单文件中设置了外部存储和互联网的权限。我是安卓系统的新手,非常感谢您的帮助。

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

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>

日志记录错误:

致命例外: 总部 无法启动活动 Component entInfo { com.example.demo/com.example.demo. MainActivity } : android.os. NetworkOnMainThreadException ActivityThread.PerformLaunchActivity (ActivityThread.java: 1956) ActivityThread.handleLaunchActivity (ActivityThread.java: 1981) ActivityThread.access $600(ActivityThread.java: 123) ActivityThread $H.handleMessage (ActivityThread.java: 1147) 在 android.os 处理器。调度消息(Handler.java: 99) 在 android.os. Looper.loop (Looper.java: 137) ActivityThread.main (ActivityThread.java: 4424) 原生方法(本机方法) 在 java.lang.response. Method.emon (Method.java: 511) ZygoteInit $MethodAndArgsCaller.run (ZygoteInit.java: 784) JygoteInit.main (ZygoteInit.java: 551) 在 dalvik.system. NativeStart.main (本机方法) 由 android.os. NetworkOnMainThreadException 引起 StrictMode $AndroidBlockGuardPolicy. onNetwork (StrictMode.java: 1099) 在 java.net. InetAdresss.lookupHostByName (InetAdresss.java: 391) 在 java.net. InetAddresss.getAllByNameImpl (InetAddresss.java: 242) 在 java.net. InetAddresss.getAllByName (InetAddresss.java: 220) 在 libcore.net.http. HttpConnection (HttpConnection.java: 71) 在 libcore.net.http. HttpConnection (HttpConnection.java: 50) 在 libcore.net.http. HttpConnection $Address.connect (HttpConnection.java: 351) 在 libcore.net.http. HttpConnectionPool.get (HttpConnectionPool.java: 86) 在 libcore.net.http. HttpConnection.connect (HttpConnection.java: 128) 在 libcore.net.http. HttpEngine.openSocketConnection (HttpEngine.java: 308) 在 libcore.net.http. HttpEngine.connect (HttpEngine.java: 303) 请访问 libcore.net.http. HttpEngine.sendSocketRequest (HttpEngine.java: 282) 请访问 libcore.net.http. HttpEngine.sendRequest (HttpEngine.java: 232) 请访问 libcore.net.http. HttpURLConnectionImp.getResponse (HttpURLConnectionImp.java: 273) 在 libcore.net.http. HttpURLConnectionImp.getInputStream (HttpURLConnectionImp.java: 168) (网址 java.net.URL.openStream: 462) 可以访问 com.example.demo. MainActivity. DownloadFiles (MainActivity.java: 30) 在 com.example.demo. MainActivity.onCreate (MainActivity.java: 24) 创建(Activity.java: 4465) 在 android.app. Instrumentation.calActivityOnCreate (Instrumentation.java: 1049) ActivityThread.PerformLaunchActivity (ActivityThread.java: 1920)

剪辑

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

当我在模拟器中运行这段代码时,代码仍然无法工作-文件没有被下载。

262042 次浏览

使用 AsyncTask

把你的下载文件代码在它的 doinbackground。。

Android 不再允许在主线程上执行繁重的任务,以避免 ANR (应用程序不响应)错误

在主线程上执行网络操作是不好的做法,这就是为什么会看到 NetworkOnMainThreadException。这项政策阻止了这种情况的发生。如果您确实必须为了测试而这样做,那么在 OnCreate 中放入以下内容:

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

请记住,这是非常糟糕的做法,这样做,并应理想地移动您的网络代码为 AsyncTaskThread

使用 异步任务

当您想要下载文件时调用: 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<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 connection = url.openConnection();
connection.connect();


// this will be useful so that you can show a tipical 0-100%
// progress bar
int lenghtOfFile = connection.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);


}


}
}

如果不能在4.0中工作,那么添加:

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

应该使用 AsyncTask (或其他方式在后台执行网络操作)。

@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<Void, Void, Void>{


//execute on background (out of the UI thread)
protected Long doInBackground(URL... urls) {
DownloadFiles();
}


}

关于 Android 文档上的 AsyncTask 的更多信息

希望能有帮助。

在线程或 AsyncTask 中运行这些代码。为了避免重复调用 same _ url (一次是 getContentLlength () ,一次是 openStream ()) ,使用 Apache 的 IOUtils.toByteArray。

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

除了使用 AsyncTask 之外,您还可以将操作放在 runnable-中

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 handler..such as updating a textview etc..

Iam4fun 先生,你的代码答案在这里. . 你将使用线程..。

   findViewById(R.id.download).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
           

new Thread(new Runnable() {
public void run() {
DownloadFiles();
}
}).start();

然后..。

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

禁止从 api 级别11或蜂巢开始在主线程上进行网络操作。使用线程或异步任务。更多信息请访问 https://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

简单的 Kotlin 版本

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

有没有办法从这个方法得到下载进度或下载大小?

这与 InputStream.copyTo中定义的实现相同,但是有所进展

/*inline*/ 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
}
}
}

一个用法的例子:

val handler = object : Handler(Looper.getMainLooper()) {


override fun handleMessage(msg: Message) {
// length may be negative because it is based on http header
val (progress, length) = msg.obj as Pair<Long, Long>
}
}


// call this outside of main thread
val totalSize = download("http://example.site/path/to/file", "path/to/file") { progress, length ->
// handling the result on main thread
handler.sendMessage(handler.obtainMessage(0, progress to length))
}

我建议使用 Android 下载管理器

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

下载文件

    DownloadManager downloadmanager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
Uri uri = Uri.parse("https://www.globalgreyebooks.com/content/books/ebooks/game-of-life.pdf");


DownloadManager.Request request = new DownloadManager.Request(uri);
request.setTitle("My File");
request.setDescription("Downloading");//request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"game-of-life");
downloadmanager.enqueue(request);

下面的代码帮助您从服务器上下载文件,同时可以在您的状态栏上看到下载的进度。

请看下图中我的代码的功能:

enter image description here enter image description here

STEP-1: 下载 FileFromURL.java类文件上创建,从服务器下载文件内容。这里我创建了一个异步任务来下载文件。

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

注意: 如果您想要带导入包的代码,那么 点击这里

现在步骤2: 您需要在您的 click 事件上调用上面的 ayncronic 任务。例如,我已经设置了 pdf 图像图标。 使用以下代码调用 AsyncTask:

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

注意: 这里您可以在文件参数中看到 文件名变量。这是我用来保存我的本地设备下载文件的名称。目前我只下载 pdf 文件,但你可以使用你的网址在 ServerFileUrl参数。

当你点击下载按钮,首先你必须创建本地存储路径,你想保存它,我们应该把下载文件功能到 ExecutorService (这是用来代替 AsyncTask,因为 AsyncTask 是不推荐的)。

// 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
}
}
}

网址下载文件的功能

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

这是我如何下载使用改造,保存和返回一个文件到视图模型:)

接口 FileDownloader { 同伴物体{ Private val 实例: FileDownloader by 惰性{

        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()

所有的答案都是真的写了很多代码而不干净我最好的答案是:

SetOnClickListener (view-> {

        Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse(YOUR_URL);
startActivity(intent);
        

});

或使用图书馆下载:

下载

连结:

Https://github.com/mindorksopensource/prdownloader

基于 弗拉德的回答很好,这里有一个非阻塞且相当简单的 kotlin 版本,它允许您提供一个回调,这样您就可以在下载完成(或错误)时访问该文件:

/** Start downloading to the given local path, and call the completionCallback with the local file when done. */
fun startDownload(link: String, path: String, completionCallback: (Result<File>) -> Unit) {
thread {
val outputFile = File(path)
try {
URL(link).openStream().use { input ->
FileOutputStream(File(path)).use { output ->
input.copyTo(output)
}
}
} catch (err: Exception) {
completionCallback(Result.failure(err))
return@thread
}
completionCallback(Result.success(outputFile))
}
}

示例使用(来自活动) :

startDownload(
link = getExternalFilesDir(null)!!.resolve("my_file.json").path,
path = "https://api.plos.org/search?q=title:DNA",
) { result: Result<File> ->
result.getOrNull()?.let {
println("Got file: ${result.getOrNull()?.absolutePath}")
localModels = reloadLocalModels()
updateModelListDisplay()
} ?: println(result.exceptionOrNull()?.toString() ?: "Error with no message")
}