Ada banyak cara untuk mengunduh file. Mengikuti Saya akan memposting cara yang paling umum; Terserah Anda untuk memutuskan metode mana yang lebih baik untuk aplikasi Anda.
1. Gunakan AsyncTask
dan tunjukkan progres unduhan dalam dialog
Metode ini akan memungkinkan Anda untuk menjalankan beberapa proses latar belakang dan memperbarui UI secara bersamaan (dalam hal ini, kami akan memperbarui bilah kemajuan).
Impor:
import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
Ini adalah contoh kode:
// 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
}
});
The AsyncTask
akan terlihat seperti ini:
// 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;
}
Metode di atas ( doInBackground
) selalu berjalan di utas latar belakang. Anda seharusnya tidak melakukan tugas UI di sana. Di sisi lain, onProgressUpdate
dan onPreExecute
jalankan di utas UI, sehingga Anda dapat mengubah bilah kemajuan:
@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();
}
Agar ini dapat berjalan, Anda memerlukan izin WAKE_LOCK.
<uses-permission android:name="android.permission.WAKE_LOCK" />
2. Unduh dari Layanan
Pertanyaan besar di sini adalah: bagaimana cara saya memperbarui aktivitas saya dari suatu layanan? . Dalam contoh berikut kita akan menggunakan dua kelas yang mungkin tidak Anda sadari: ResultReceiver
dan IntentService
. ResultReceiver
adalah yang akan memungkinkan kami untuk memperbarui utas kami dari suatu layanan; IntentService
adalah subclass Service
yang memunculkan thread untuk melakukan pekerjaan latar belakang dari sana (Anda harus tahu bahwa Service
running sebenarnya di thread yang sama dari aplikasi Anda; ketika Anda meluas Service
, Anda harus secara manual menelurkan thread baru untuk menjalankan operasi pemblokiran CPU).
Layanan unduhan dapat terlihat seperti ini:
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);
}
}
Tambahkan layanan ke manifes Anda:
<service android:name=".DownloadService"/>
Dan aktivitasnya akan terlihat seperti ini:
// 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);
Ini dia ResultReceiver
datang untuk bermain:
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 Gunakan perpustakaan Groundy
Groundy adalah pustaka yang pada dasarnya membantu Anda menjalankan potongan kode di layanan latar belakang, dan didasarkan padaResultReceiver
konsep yang ditunjukkan di atas. Perpustakaan ini sudah usang saat ini. Beginilah keseluruhan kode akan terlihat seperti:
Aktivitas tempat Anda menampilkan dialog ...
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;
}
}
};
}
Sebuah GroundyTask
implementasi digunakan oleh Groundy untuk men-download file dan menunjukkan kemajuan:
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;
}
}
}
Dan tambahkan ini ke manifes:
<service android:name="com.codeslap.groundy.GroundyService"/>
Tidak mungkin lebih mudah menurutku. Ambil saja toples terbaru dari Github dan Anda siap berangkat. Perlu diingat bahwa tujuan utama Groundy adalah untuk membuat panggilan ke apek REST eksternal dalam layanan latar belakang dan memposting hasil ke UI dengan mudah. Jika Anda melakukan hal seperti itu di aplikasi Anda, itu bisa sangat berguna.
3. Gunakan DownloadManager
kelas ( GingerBread
dan yang lebih baru saja)
GingerBread membawa fitur baru DownloadManager
,, yang memungkinkan Anda mengunduh file dengan mudah dan mendelegasikan kerja keras menangani utas, stream, dll. Ke sistem.
Pertama, mari kita lihat metode utilitas:
/**
* @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;
}
Nama metode menjelaskan semuanya. Setelah yakin DownloadManager
tersedia, Anda dapat melakukan sesuatu seperti ini:
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);
Kemajuan unduhan akan ditampilkan di bilah notifikasi.
Pikiran terakhir
Metode pertama dan kedua hanyalah puncak gunung es. Ada banyak hal yang harus diingat jika Anda ingin aplikasi Anda menjadi kuat. Berikut daftar singkatnya:
- Anda harus memeriksa apakah pengguna memiliki koneksi internet yang tersedia
- Pastikan Anda memiliki izin yang tepat (
INTERNET
dan WRITE_EXTERNAL_STORAGE
); juga ACCESS_NETWORK_STATE
jika Anda ingin memeriksa ketersediaan internet.
- Pastikan direktori yang akan Anda unduh ada file dan memiliki izin menulis.
- Jika unduhan terlalu besar, Anda mungkin ingin menerapkan cara untuk melanjutkan unduhan jika upaya sebelumnya gagal.
- Pengguna akan berterima kasih jika Anda mengizinkan mereka mengganggu unduhan.
Kecuali jika Anda memerlukan kontrol terperinci dari proses unduhan, maka pertimbangkan untuk menggunakan DownloadManager
(3) karena sudah menangani sebagian besar item yang tercantum di atas.
Tetapi juga pertimbangkan bahwa kebutuhan Anda dapat berubah. Misalnya, DownloadManager
tidak ada caching respons . Ini akan membabi buta mengunduh file besar yang sama beberapa kali. Tidak ada cara mudah untuk memperbaikinya setelah fakta. Di mana jika Anda mulai dengan dasar HttpURLConnection
(1, 2), maka yang Anda butuhkan adalah menambahkan HttpResponseCache
. Jadi upaya awal mempelajari alat dasar dan standar dapat menjadi investasi yang baik.
Kelas ini sudah tidak digunakan lagi di API level 26. ProgressDialog adalah dialog modal, yang mencegah pengguna berinteraksi dengan aplikasi. Alih-alih menggunakan kelas ini, Anda harus menggunakan indikator progres seperti ProgressBar, yang dapat disematkan di UI aplikasi Anda. Atau, Anda dapat menggunakan notifikasi untuk memberi tahu pengguna tentang kemajuan tugas. Untuk lebih jelasnya, Tautkan