Скачайте файл с Android и покажите прогресс в ProgressDialog

Сгенерировать строку запроса в PreparedStatement, чтобы число соответствовало количеству элементов в вашем списке. Вот пример:

public void myQuery(List<String> items, int other) {
  ...
  String q4in = generateQsForIn(items.size());
  String sql = "select * from stuff where foo in ( " + q4in + " ) and bar = ?";
  PreparedStatement ps = connection.prepareStatement(sql);
  int i = 1;
  for (String item : items) {
    ps.setString(i++, item);
  }
  ps.setInt(i++, other);
  ResultSet rs = ps.executeQuery();
  ...
}

private String generateQsForIn(int numQs) {
    String items = "";
    for (int i = 0; i < numQs; i++) {
        if (i != 0) items += ", ";
        items += "?";
    }
    return items;
}
1003
задан atish shimpi 26 November 2014 в 14:42
поделиться

1 ответ

Есть много способов загрузить файлы. Ниже я опубликую наиболее распространенные способы; Вам решать, какой метод лучше для вашего приложения.

1. Используйте AsyncTask и покажите прогресс загрузки в диалоговом окне

Этот метод позволит вам одновременно выполнять некоторые фоновые процессы и обновлять пользовательский интерфейс (в этом случае мы обновим индикатор выполнения) .

Импорт:

import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;

Это пример кода:

// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;

// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);

// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

    @Override
    public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true); //cancel the task
    }
});

AsyncTask будет выглядеть так:

// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {

    private Context context;
    private PowerManager.WakeLock mWakeLock;

    public DownloadTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            // expect HTTP 200 OK, so we don't mistakenly save error report
            // instead of the file
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP " + connection.getResponseCode()
                        + " " + connection.getResponseMessage();
            }

            // this will be useful to display download percentage
            // might be -1: server did not report the length
            int fileLength = connection.getContentLength();

            // download the file
            input = connection.getInputStream();
            output = new FileOutputStream("/sdcard/file_name.extension");

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return e.toString();
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }
        return null;
    }

Метод выше ( doInBackground ) всегда выполняется в фоновом режиме. нить. Вы не должны выполнять здесь никаких задач пользовательского интерфейса. С другой стороны, onProgressUpdate и onPreExecute выполняются в потоке пользовательского интерфейса, поэтому вы можете изменить индикатор выполнения:

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user 
        // presses the power button during download
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
             getClass().getName());
        mWakeLock.acquire();
        mProgressDialog.show();
    }

    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setMax(100);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        mProgressDialog.dismiss();
        if (result != null)
            Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    }

Для запуска вам потребуется разрешение WAKE_LOCK.

<uses-permission android:name="android.permission.WAKE_LOCK" />

2. Загрузить из службы

Большой вопрос: как мне обновить данные о моей активности из службы? . В следующем примере мы собираемся использовать два класса, о которых вы можете не знать: ResultReceiver и IntentService . ResultReceiver - это тот, который позволит нам обновлять наш поток из службы; IntentService является подклассом Service , который порождает поток для выполнения фоновой работы оттуда (вы должны знать, что служба фактически выполняется в том же потоке вашего приложения ; когда вы расширяете Service , вы должны вручную создавать новые потоки для выполнения операций блокировки ЦП).

Служба загрузки может выглядеть так:

public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;

    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {

        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        try {

            //create url and connect
            URL url = new URL(urlToDownload);
            URLConnection connection = url.openConnection();
            connection.connect();

            // this will be useful so that you can show a typical 0-100% progress bar
            int fileLength = connection.getContentLength();

            // download the file
            InputStream input = new BufferedInputStream(connection.getInputStream());

            String path = "/sdcard/BarcodeScanner-debug.apk" ;
            OutputStream output = new FileOutputStream(path);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;

                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }

            // close streams 
            output.flush();
            output.close();
            input.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

        Bundle resultData = new Bundle();
        resultData.putInt("progress" ,100);

        receiver.send(UPDATE_PROGRESS, resultData);
    }
}

Добавьте службу в свой манифест:

<service android:name=".DownloadService"/>

И действие будет выглядеть так:

// initialize the progress dialog like in the first example

// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);

Вот ResultReceiver вступает в игру:

private class DownloadReceiver extends ResultReceiver{

    public DownloadReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

        super.onReceiveResult(resultCode, resultData);

        if (resultCode == DownloadService.UPDATE_PROGRESS) {

            int progress = resultData.getInt("progress"); //get the progress
            dialog.setProgress(progress);

            if (progress == 100) {
                dialog.dismiss();
            }
        }
    }
}

2.1 Использование библиотеки Groundy

Groundy - это библиотека, которая в основном помогает вам запускать фрагменты кода в фоновой службе, и она основана на концепции ResultReceiver , показанной выше. Эта библиотека устарела на данный момент. Вот как будет выглядеть весь код :

Действие, в котором вы показываете диалог ...

public class MainActivity extends Activity {

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
                Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
                Groundy.create(DownloadExample.this, DownloadTask.class)
                        .receiver(mReceiver)
                        .params(extras)
                        .queue();

                mProgressDialog = new ProgressDialog(MainActivity.this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();
            }
        });
    }

    private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            switch (resultCode) {
                case Groundy.STATUS_PROGRESS:
                    mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
                    break;
                case Groundy.STATUS_FINISHED:
                    Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
                    mProgressDialog.dismiss();
                    break;
                case Groundy.STATUS_ERROR:
                    Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    break;
            }
        }
    };
}

Реализация GroundyTask , используемая Groundy ], чтобы загрузить файл и показать прогресс:

public class DownloadTask extends GroundyTask {    
    public static final String PARAM_URL = "com.groundy.sample.param.url";

    @Override
    protected boolean doInBackground() {
        try {
            String url = getParameters().getString(PARAM_URL);
            File dest = new File(getContext().getFilesDir(), new File(url).getName());
            DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
            return true;
        } catch (Exception pokemon) {
            return false;
        }
    }
}

И просто добавьте это в манифест:

<service android:name="com.codeslap.groundy.GroundyService"/>

Думаю, проще некуда. Просто возьмите последнюю версию jar из Github , и все готово. Имейте в виду, что основная цель Groundy - выполнять вызовы внешних API REST в фоновой службе и легко публиковать результаты в пользовательском интерфейсе. Если вы делаете что-то подобное в своем приложении, это может быть действительно полезно.

2.2 Используйте https://github.com/koush/ion

3. Используйте класс DownloadManager (только GingerBread и новее).

GingerBread предлагает новую функцию, DownloadManager , которая позволяет легко загружать файлы и делегировать тяжелую работу. обработки потоков, потоков и т. д. в систему.

Во-первых, давайте посмотрим на служебный метод:

/**
 * @param context used to check the device version and DownloadManager information
 * @return true if the download manager is available
 */
public static boolean isDownloadManagerAvailable(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        return true;
    }
    return false;
}

Название метода все объясняет.Убедившись, что DownloadManager доступен, вы можете сделать что-то вроде этого:

String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");

// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

Ход загрузки будет отображаться на панели уведомлений.

Заключительные мысли

Первый и второй методы - лишь верхушка айсберга. Если вы хотите, чтобы ваше приложение было надежным, нужно помнить о многих вещах. Вот краткий список:

  • Вы должны проверить, есть ли у пользователя доступ к Интернету.
  • Убедитесь, что у вас есть необходимые разрешения ( ИНТЕРНЕТ и WRITE_EXTERNAL_STORAGE ); также ACCESS_NETWORK_STATE , если вы хотите проверить доступность Интернета.
  • Убедитесь, что каталог, в который вы собираетесь загружать файлы, существует и имеет права на запись.
  • Если загрузка слишком велика, вы можете реализовать способ возобновления загрузки, если предыдущие попытки не удались.
  • Пользователи будут благодарны, если вы позволите им прервать загрузку.

Если вам не нужен подробный контроль над процессом загрузки, рассмотрите возможность использования DownloadManager (3), потому что он уже обрабатывает большинство элементов, перечисленных выше.

Но также учтите, что ваши потребности могут измениться. Например, DownloadManager не кэширует ответы . Он будет слепо загружать один и тот же большой файл несколько раз. Нет простого способа исправить это постфактум. Если вы начинаете с простого HttpURLConnection (1, 2), то все, что вам нужно, это добавить HttpResponseCache . Таким образом, начальные усилия по изучению основных стандартных инструментов могут быть хорошей инвестицией.

Этот класс объявлен устаревшим на уровне API 26.ProgressDialog - это модальный диалог, который не позволяет пользователю взаимодействовать с приложением. Вместо для использования этого класса вы должны использовать индикатор прогресса, например ProgressBar, который можно встроить в пользовательский интерфейс вашего приложения. В качестве альтернативы, вы можете использовать уведомление, чтобы информировать пользователя о ходе выполнения задачи.Подробнее Ссылка

1846
ответ дан 19 December 2019 в 20:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: