在 Android Studio 中下载文件需要很长时间

File taking a long time to download in Android Studio

当我在 Android Studio 中启动我的应用程序时,我必须将一个文件从我的资产文件夹转换为一个文件,以便将其作为 RDF 模型读取。问题是我的文件现在越来越大,应用程序通常会崩溃,或者文件下载时间太长。该文件大约有 170.384 MB,所以它是一个相当大的文件,但我预计在我完成之前该文件会增长到 1GB 左右。我在这里搜索了关于如何让文件下载更快的答案,但我没有看到任何我没有尝试过的新内容。例如,我启动了一个 AsyncTask,以便在与主 UI 线程不同的线程上执行 "download" 操作。这阻止了我的应用程序崩溃,但文件下载时间仍然太长,而且通常会超时。这是我在 AsyncTask 中下载文件的代码示例:

 @Override
 public Model doInBackground(String... params){
        Model tdb = null;
        try {
            String filePath = context.getFilesDir() + File.separator + "my_turtle.ttl";
            File destinationFile = new File(filePath);
            FileOutputStream outputStream = new FileOutputStream(destinationFile);
            AssetManager assetManager = context.getAssets();
            InputStream inputStream = assetManager.open("sample_3.ttl");
            byte[] buffer = new byte[1024];
            int length = 0;
            int per = 0;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                publishProgress(per);
                per++;
            }
            inputStream.close();
            outputStream.close();


            Dataset dataset = TDBFactory.createDataset();
            tdb = dataset.getNamedModel("my_dataset.ttl");
            ///Model m = FileManager.get().loadModel(FileManager.get().readWholeFileAsUTF8(inputStream));
            TDBLoader.loadModel(tdb, filePath, false);
            model = tdb;
            MainActivity.presenter.setModel(model);
        }catch(java.io.FileNotFoundException e){
            e.printStackTrace(System.out);
        }
        catch(java.io.IOException e){
            e.printStackTrace(System.out);
        }
        return tdb;
    }

如您所见,我必须创建一个新的文件路径并创建一个新文件,创建一个 InputStream 以便从资产中读取文件,并将 InputStream 写入文件以便在 TDB 中加载 RDF 模型店铺。正是在这个过程中,我的应用程序开始在 AsyncTask 中 "time out"。

我遇到的另一个问题是在加载文件时更新我的​​进度条。我不确定如何获取 InputStream 的长度,我在我的代码中做了这样的事情:

while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                publishProgress(per); //Publishing progress here...
                per++;
            }

发布进度需要触发onProgressUpdate方法():

@Override
public void onProgressUpdate(Integer... progress){
        progressBar.setProgress(progress[0]);
        pd.setProgress(progress[0]);
    }

但出于某种原因,我的 ProgressBar 和 ProgressDialog 在整个上传时间保持在 0%(即使我使用较小的文件上传)。我不确定为什么会这样。

下面是我的 AsyncTask class 的完整代码。我想 post 代码的相关部分,但它们可能在我的代码的更广泛上下文中引起了问题:

 public class DownloadModel extends AsyncTask<String, Integer, Model> {
    Context context;
    Model model = null;
    ProgressDialog pd;

    public DownloadModel(Context context){
        this.context = context;
        this.pd = new ProgressDialog(context);
    }

    @Override
    public Model doInBackground(String... params){
        Model tdb = null;
        try {
            String filePath = context.getFilesDir() + File.separator + "my_turtle.ttl";
            File destinationFile = new File(filePath);
            FileOutputStream outputStream = new FileOutputStream(destinationFile);
            AssetManager assetManager = context.getAssets();
            InputStream inputStream = assetManager.open("sample_3.ttl");
            byte[] buffer = new byte[10000000];
            int length = 0;
            int per = 0;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                publishProgress(per);
                per++;
            }
            inputStream.close();
            outputStream.close();


            Dataset dataset = TDBFactory.createDataset();
            tdb = dataset.getNamedModel("my_dataset.ttl");
            ///Model m = FileManager.get().loadModel(FileManager.get().readWholeFileAsUTF8(inputStream));
            TDBLoader.loadModel(tdb, filePath, false);
            model = tdb;
            MainActivity.presenter.setModel(model);
        }catch(java.io.FileNotFoundException e){
            e.printStackTrace(System.out);
        }
        catch(java.io.IOException e){
            e.printStackTrace(System.out);
        }
        return tdb;
    }

    @Override
    public void onProgressUpdate(Integer... progress){
        progressBar.setProgress(progress[0]);
        pd.setProgress(progress[0]);
    }

    @Override
    public void onPreExecute(){
        pd.setMessage("Loading Knowledgebase...");
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMax(100);
        pd.show();
    }

    @Override
    public void onPostExecute(Model i){
        progressBar.setVisibility(View.GONE);
        pd.dismiss();
    }
  }

感谢您的帮助!

How to show progressbar

输入流的长度与文件大小相同(以字节为单位)。正如您知道文件的大小,只需乘以 1024*1024 将其从 Mb 转换为字节,您就可以使用这个硬编码值。

在 doInBackground 方法中更新 while 循环,如下所示

int size = 0;
        while ((length = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, length);
            size += length;
            publishProgress(size*100/your_file_size_in_bytes);
        }

如果您处理的是单个文件,则无法加快该过程。

但是,如果您有多个文件,您可以 运行 使用 ThreadPoolExecutor 并行处理多个线程。

我最终找到了一个非常不同的解决方案。如果有人遇到为 Android Studio 应用程序上传大文件的类似问题,只需考虑使用后端服务器来存储数据。这是我最终做出的决定,因为将大文件直接下载到应用程序需要很长时间,因为移动设备的内存有限。从计算机 运行 服务器并连接 phone 上的客户端以在适当的时间检索相关信息更有意义。否则,您最终将拥有一个文件,该文件会耗尽移动设备上的存储空间,这将使您的最终用户的性能大大降低。我最终决定将 RDF 文件存储在计算机上,将文件上传到计算机上,运行 一个 Java 服务器套接字,以便用户从应用程序连接客户端,然后简单地查询计算机上的文件,并 return 向用户提供适当的信息。这提高了我的应用程序性能并结束了 10 分钟的下载时间,这对于应用程序来说是不可接受的。