76

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

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>

日志错误:

致命异常:主 java.lang.RuntimeException:无法启动活动 ComponentInfo{com.example.demo/com.example.demo.MainActivity}:android.os.NetworkOnMainThreadException 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956 ) 在 android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981) 在 android.app.ActivityThread.access$600(ActivityThread.java:123) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147) 在android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:137) 在 android.app.ActivityThread.main(ActivityThread.java:4424) 在 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) 原因:android.os。 NetworkOnMainThreadException 在 android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099) 在 java.net.InetAddress.lookupHostByName(InetAddress.java:391) 在 java.net.InetAddress.getAllByNameImpl(InetAddress.java:242) 在 java .net.InetAddress.getAllByName(InetAddress.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.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:273) 在 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) 在 android.app.Activity.performCreate(Activity.java:4465) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 在 android.app.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);
        }
    }
}

当我在模拟器中运行此代码时,代码仍然不起作用 - 文件没有被下载。

4

14 回答 14

91

使用异步任务

当你想下载文件时调用: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); 
于 2013-04-02T07:57:29.540 回答
60

简单的 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))
}
于 2018-06-17T20:02:42.760 回答
44

我会推荐使用 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);
于 2018-07-22T14:03:32.997 回答
14

使用下载管理器下载文件

    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);
于 2019-11-21T21:42:37.097 回答
10

在主线程上执行网络操作是不好的做法,这就是您看到NetworkOnMainThreadException. 它被政策所阻止。如果您确实必须这样做以进行测试,请将以下内容放入您的 OnCreate:

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

请记住,这样做是非常糟糕的做法,理想情况下应该将您的网络代码移动到一个AsyncTask或一个Thread.

于 2013-04-02T07:54:54.223 回答
3

Mr.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);
          }
}
}
于 2016-11-02T06:55:15.960 回答
0

使用AsyncTask

将您的下载文件代码放入doinbackground其中..

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

于 2013-04-02T07:54:48.257 回答
0

您应该使用 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 的更多信息

希望能帮助到你。

于 2013-04-02T08:00:59.580 回答
0

在线程或 AsyncTask 中运行这些代码。为了避免重复调用相同的_url(一次getContentLength(),一次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;
    }
}
于 2014-02-04T21:03:49.227 回答
0

除了使用 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..
于 2016-09-12T18:32:33.283 回答
0

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

请参阅我的代码下图中的功能:

在此处输入图像描述 在此处输入图像描述

步骤 - 1:在DownloadFileFromURL.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 步:您需要在点击事件上调用上述异步任务。例如,我设置了 pdf 图像图标。要调用 AsyncTask,请使用以下代码:

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

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

于 2020-04-15T11:21:13.867 回答
0

当您点击下载按钮时,首先您必须创建要保存它的本地存储路径,我们应该将下载文件功能放入 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
        }
    }
}

从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
        }
    }
}
于 2021-05-06T23:12:32.947 回答
0

这就是我使用改造下载、保存文件并将文件返回到视图模型的方式:)

接口 FileDownloader { 伴侣对象 { 私有 val 实例:懒惰的 FileDownloader {

        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()
于 2021-09-03T11:54:31.647 回答
-1

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

于 2017-11-20T10:53:19.387 回答