Как скачать PDF-файл в Android?
Я хочу скачать PDF-файл с URL. Для просмотра PDF-файла я использовал код ниже.
File file = new File("/sdcard/example.pdf");
if (file.exists()) {
Uri path = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(path, "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(OpenPdf.this, "No Application Available to View PDF",
Toast.LENGTH_SHORT).show();
}
}
Это работает, но как мне получить PDF-файл из URL (например, http://.../example.pdf
). Я хочу скачать PDF-файл с этого URL. Пожалуйста, помогите мне. Заранее спасибо.
5 ответов
Загрузка PDF работает так же, как загрузка любого другого двоичного файла.
- Открыть
HttpUrlConnection
- Используйте соединение
getInputStream()
метод для чтения файла. - Создать
FileOutputStream
и напишите входной поток.
Проверьте этот пост на примере исходного кода.
Скачать PDF:
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("www.education.gov.yk.ca/pdf/pdf-test.pdf")));
Ах, как я только что узнал, это зависит от устройства.
сценарии
Он загрузит PDF в ваш браузер / скачал / папку
У вас есть аккаунт Google Docs - он попросит вас войти, а затем просмотреть PDF в браузере.
У вас установлено приложение для чтения PDF - приложение может зависеть, может не
Во всех сценариях пользователь имеет доступ к PDF с одной строкой кода:-)
Есть много способов загрузки файлов. После я опубликую наиболее распространенные способы; Вам решать, какой метод лучше подходит для вашего приложения.
1. Используйте AsyncTask
и показать прогресс загрузки в диалоговом окне
Этот метод позволит вам выполнять некоторые фоновые процессы и обновлять пользовательский интерфейс одновременно (в этом случае мы будем обновлять индикатор выполнения).
Это пример кода:
// 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);
}
});
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
фактически работает в той же ветке вашего приложения; когда ты расширяешься 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 {
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());
OutputStream output = new FileOutputStream("/sdcard/BarcodeScanner-debug.apk");
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);
}
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");
mProgressDialog.setProgress(progress);
if (progress == 100) {
mProgressDialog.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"/>
Это не может быть проще, я думаю. Просто возьмите последнюю банку с 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);
Ход загрузки будет отображаться в панели уведомлений.
Последние мысли
Первый и второй методы - лишь вершина айсберга. Есть много вещей, которые вы должны иметь в виду, если вы хотите, чтобы ваше приложение было надежным. Вот краткий список:
- Вы должны проверить, есть ли у пользователя доступ к интернету
- Убедитесь, что у вас есть нужные разрешения (
INTERNET
а такжеWRITE_EXTERNAL_STORAGE
); такжеACCESS_NETWORK_STATE
если вы хотите проверить доступность интернета. - Убедитесь, что каталог, в который вы собираетесь загружать файлы, существует и имеет права на запись.
- Если загрузка слишком велика, вы можете реализовать способ возобновить загрузку, если предыдущие попытки не увенчались успехом.
- Пользователи будут благодарны, если вы позволите им прервать загрузку.
Если вам не нужен подробный контроль над процессом загрузки, тогда подумайте об использовании DownloadManager
(3) потому что он уже обрабатывает большинство предметов, перечисленных выше.
Но также учтите, что ваши потребности могут измениться. Например, DownloadManager
не кэширует ответ. Он будет слепо загружать один и тот же большой файл несколько раз. Там нет простого способа исправить это после факта. Где, если вы начнете с базового HttpURLConnection
(1, 2), тогда все, что вам нужно, это добавить HttpResponseCache
, Таким образом, первоначальные усилия по изучению основных стандартных инструментов могут стать хорошим вложением.
Нет необходимости помещать длинный код для открытия и загрузки PDF в Android, вы можете просто использовать приведенный ниже код для открытия и загрузки PDF
String URL ="http://worldhappiness.report/wp-content/uploads/sites/2/2016/03/HR-V1_web.pdf"
startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse(URL)));
public static class Downloader {
public static void DownloadFile(String fileURL, File directory) {
try {
FileOutputStream file = new FileOutputStream(directory);
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url .openConnection();
connection .setRequestMethod("GET");
connection .setDoOutput(true);
connection .connect();
InputStream input = connection .getInputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = input .read(buffer)) > 0) {
file .write(buffer, 0, len );
}
file .close();
} catch (Exception e) {
e.printStackTrace();
}
}
Для получения дополнительной информации нажмите здесь http://androiddhina.blogspot.in/2015/09/how-to-download-pdf-from-url-in-android.html