Загрузка большого файла (> 100 МБ) на Honeycomb в AsyncTask замедляет интерфейс, возможно, из-за GC? - PullRequest
4 голосов
/ 18 августа 2011

У меня есть личный внутренний класс DownloadFileAsyncTask в одном из моих занятий. Я прикрепил это:

private class DownloadFileAsyncTask extends AsyncTask<URL, Integer, Boolean> {
    private static final String TAG = "DownloadFileAsyncTask";

    @Override
    protected void onPreExecute() {
        WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        mWifiLock           = manager.createWifiLock("wifilock");

        mWifiLock.acquire();
    }

    @Override
    protected Boolean doInBackground(URL... params) {
        try {
            URLConnection urlConnection = params[0].openConnection();
            urlConnection.connect();

            InputStream      in  = urlConnection.getInputStream();
            FileOutputStream out = openFileOutput("archive.zip", Context.MODE_PRIVATE);

            int fileSize = urlConnection.getContentLength();
            if (fileSize == 0) {
                return false;
            }

            int downloadedSize = 0;

            byte[] data = new byte[1024];
            int count   = 0;

            while ((count = in.read(data)) != -1) {
                if (isCancelled()) {
                    Log.d(TAG, "Download cancelled.");

                    out.close();
                    in.close();
                    return false;
                }

                out.write(data, 0, count);
                downloadedSize += count;

                publishProgress(downloadedSize, fileSize);
            }

            out.close();
            in.close();
        }
        catch (Exception ex) {
            Log.e(TAG, "doInBackground()", ex);

            return false;
        }

        return true;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int downloadedSize = values[0];
        int fileSize       = values[1];

        int progressPercent = ((int) ((downloadedSize / (float) fileSize) * 100));

        mDownloadButton.setText(String.format("%.1f MB", downloadedSize / 1048576f));
        mProgressBar.setProgress(progressPercent);
    }

    @Override
    protected void onPostExecute(Boolean result) {
    }

    @Override
    protected void onCancelled() {
        mWifiLock.release();
    }
}

Этот код работает. Файл загружен, и мой ProgressBar обновлен правильно. У меня также есть кнопка отмены, которую пользователь может нажать, чтобы закрыть загрузку. Это также работает, однако, когда я нажимаю кнопку, регистрация кнопки занимает несколько секунд (я тестирую на оборудовании). Когда я смотрю logcat во время загрузки, я вижу, что происходит много мусора. На самом деле, это кажется постоянным. Я знаю, что сборщик мусора может вызвать задержки в пользовательском интерфейсе, и моя теория заключается в том, что именно здесь происходит. Кто-нибудь испытывал это раньше? Есть ли лучший способ выполнить загрузку файла?

EDIT:

Вызов publishProgress () в конце каждой итерации основного цикла вызывал задержки. Вот обновленный код doInBackground () для решения проблемы:

@Override
protected Boolean doInBackground(URL... params) {
    try {
        URLConnection urlConnection = params[0].openConnection();
        urlConnection.connect();

        BufferedInputStream  in  = new BufferedInputStream(urlConnection.getInputStream());
        BufferedOutputStream out = new BufferedOutputStream(openFileOutput("archive.zip", Context.MODE_PRIVATE));

        int fileSize = urlConnection.getContentLength();
        if (fileSize == 0) {
            return false;
        }

        int downloadedSize = 0;

        byte[] data = new byte[1024];
        int count   = 0;

        Calendar lastUpdate = Calendar.getInstance();

        while ((count = in.read(data)) != -1) {
            if (isCancelled()) {
                Log.d(TAG, "Download cancelled.");

                out.close();
                in.close();
                return false;
            }

            out.write(data, 0, count);
            downloadedSize += count;

            Calendar now = Calendar.getInstance();
            if (now.getTimeInMillis() - lastUpdate.getTimeInMillis() >= 500) {
                lastUpdate = now;
                publishProgress(downloadedSize, fileSize);
            }
        }

        out.close();
        in.close();
    }
    catch (Exception ex) {
        Log.e(TAG, "doInBackground()", ex);

        return false;
    }

    return true;
}

1 Ответ

3 голосов
/ 18 августа 2011

Во-первых, вы могли бы набрать некоторую скорость, вызывая publishProgress (...) реже.Установите значение защиты doInBackground(...), чтобы оно вызывалось только каждые 100, 500, X миллисекунд.

Мне не удалось определить, сколько байтов считывается в ваш буфер данных за раз.Т.е. in.read(data) читает только до 1024 байтов за раз?Вместо этого вы можете использовать BufferedInputStream.

И примечание: если задача успешно завершена, вы не звоните mWifiLock.release();

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...