Загрузка файла занимает много времени в Android Studio - PullRequest
0 голосов
/ 03 ноября 2018

Когда я запускаю свое приложение в Android Studio, мне нужно преобразовать файл из папки с активами в файл, чтобы прочитать его как модель RDF. Проблема в том, что мой файл теперь становится больше, и приложение обычно вылетает или загрузка файла занимает слишком много времени. Размер файла составляет около 170,384 МБ, так что это довольно большой файл, но я ожидаю, что этот файл вырастет до 1 ГБ, прежде чем я закончил Я искал ответы здесь о том, как заставить файл загружаться быстрее, но я не увидел ничего нового, что бы я не пробовал. Например, я запустил AsyncTask, чтобы выполнить операцию «загрузки» в отдельном потоке из основного потока пользовательского интерфейса. Это остановило мое приложение от сбоя, но загрузка файла все еще занимает слишком много времени и обычно заканчивается. Вот пример моего кода, где я загружаю файл в 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;
    }

Как видите, я должен создать новый filePath и создать новый файл, создать InputStream для того, чтобы прочитать файл из ресурсов, и записать InputStream в файл, чтобы загрузить модель RDF в хранилище TDB. Именно во время этого процесса мое приложение начинает "превышать время ожидания" в AsyncTask.

Другая проблема, с которой я сталкиваюсь, - это обновление индикатора выполнения во время загрузки файла. Я не уверен, как получить длину 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. Я хотел опубликовать соответствующие части кода, но они могут быть чем-то в более широком контексте моего кода, что вызывает проблему:

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

Спасибо за вашу помощь!

Ответы [ 2 ]

0 голосов
/ 08 января 2019

В итоге я нашел совсем другое решение. Если кто-то сталкивается с аналогичной проблемой загрузки большого файла для приложения Android Studio, просто подумайте об использовании внутреннего сервера для хранения данных. В конечном итоге это решение, которое я принял, потому что загрузка большого файла напрямую в приложение займет много времени, потому что у мобильного устройства ограниченная память. Гораздо больше смысла запускать сервер с компьютера и подключать клиента к телефону для получения соответствующей информации в подходящее время. Если нет, то в конечном итоге у вас будет файл, который будет занимать место на мобильном устройстве, что значительно снизит производительность ваших конечных пользователей. В конечном итоге я решил сохранить файл RDF на компьютере, загрузить файл на компьютер, запустить сокет Java Server, чтобы пользователь мог подключить клиент из приложения, а затем просто запросить файл на компьютере и вернуть соответствующий информация для пользователя. Это улучшило производительность моих приложений и завершило 10-минутный период загрузки, что недопустимо для приложения.

0 голосов
/ 02 декабря 2018

Как показать индикатор

Длина входного потока равна размеру вашего файла в байтах. поскольку вы знаете размер вашего файла, просто преобразуйте его в байты из Мб, умножив 1024 * 1024, и вы можете использовать это жестко запрограммированное значение.

Обновите цикл while внутри вашего метода doInBackground следующим образом

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.

...