Dosyaları indirmenin birçok yolu vardır. Aşağıdaki en yaygın yolları yayınlayacağım; uygulamanız için hangi yöntemin daha iyi olduğuna karar vermek size kalmıştır.
1. AsyncTask
Bir iletişim kutusunda indirme ilerlemesini kullanma ve gösterme
Bu yöntem, bazı arka plan işlemlerini yürütmenize ve aynı zamanda kullanıcı arayüzünü güncellemenize olanak tanır (bu durumda, bir ilerleme çubuğunu güncelleyeceğiz).
İthalat:
import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;
Bu bir örnek koddur:
// 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
}
});
Bu AsyncTask
şekilde görünecek:
// 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;
}
Yukarıdaki yöntem ( doInBackground
) her zaman bir arka plan iş parçacığında çalışır. Orada herhangi bir UI görevi yapmamalısınız. Öte yandan, UI iş parçacığında onProgressUpdate
ve onPreExecute
üzerinde çalışır, böylece ilerleme çubuğunu değiştirebilirsiniz:
@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();
}
Bunun çalışması için WAKE_LOCK iznine ihtiyacınız var.
<uses-permission android:name="android.permission.WAKE_LOCK" />
2. Hizmetten İndirin
Buradaki büyük soru şudur: Etkinliğimi bir hizmetten nasıl güncelleyebilirim? . Bir sonraki örnekte, farkında olmayabileceğiniz iki sınıf kullanacağız: ResultReceiver
ve IntentService
. ResultReceiver
iş parçacığımızı bir hizmetten güncellememizi sağlayacak olan; oradan arka plan çalışması yapmak için bir iş parçacığı oluşturan IntentService
bir alt Service
sınıftır ( Service
uygulamanızın aslında aynı iş parçacığında çalıştığını bilmelisiniz ; genişlettiğinizde Service
, CPU engelleme işlemlerini çalıştırmak için yeni iş parçacıklarını el ile oluşturmanız gerekir).
İndirme hizmeti şöyle görünebilir:
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);
}
}
Hizmeti bildiriminize ekleyin:
<service android:name=".DownloadService"/>
Ve etkinlik şöyle görünecek:
// 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);
İşte ResultReceiver
oynamaya geliyorlardı:
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 kütüphanesini kullanma
Groundy , temel olarak bir arka plan hizmetinde kod parçalarını çalıştırmanıza yardımcı olan bir kitaplıktır veResultReceiver
yukarıda gösterilen konseptedayanır. Bu kütüphane şuanda kullanımdan kaldırıldı . Bu nasıl bütün kod gibi görünecektir:
İletişim kutusunu gösterdiğiniz etkinlik ...
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;
}
}
};
}
GroundyGroundyTask
tarafından dosyayı indirmek ve ilerlemeyi göstermek için kullanılan bir uygulama :
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;
}
}
}
Ve bunu manifest'e ekleyin:
<service android:name="com.codeslap.groundy.GroundyService"/>
Bence bu daha kolay olamazdı. Sadece Github'ın en yeni kavanozunu alın ve gitmeye hazırsınız. Unutmayın Groundy 'ın temel amacı kolayca ile UI için bir arka plan hizmetinde dış DİNLENME apis çağrı ve sonrası sonuçları yapmaktır. Uygulamanızda böyle bir şey yapıyorsanız, gerçekten yararlı olabilir.
3. DownloadManager
Sınıfı kullanın ( GingerBread
ve yalnızca daha yenisini)
GingerBread, DownloadManager
dosyaları kolayca indirmenize ve iş parçacıklarını, akışları, vb. İşleme zor işini sisteme devretmenizi sağlayan yeni bir özellik getirdi .
İlk olarak, bir yardımcı program yöntemine bakalım:
/**
* @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;
}
Yöntemin adı her şeyi açıklıyor. DownloadManager
Kullanılabilir olduğundan emin olduktan sonra , böyle bir şey yapabilirsiniz:
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);
İndirme işleminin ilerleme durumu bildirim çubuğunda gösterilecektir.
Son düşünceler
Birinci ve ikinci yöntemler buzdağının sadece görünen kısmıdır. Uygulamanızın sağlam olmasını istiyorsanız aklınızda bulundurmanız gereken birçok şey vardır. İşte kısa bir liste:
- Kullanıcının internet bağlantısı olup olmadığını kontrol etmelisiniz
- Doğru izinlere (
INTERNET
ve WRITE_EXTERNAL_STORAGE
) sahip olduğunuzdan emin olun ; Ayrıca ACCESS_NETWORK_STATE
internet kullanılabilirliğini kontrol etmek istiyorsanız.
- Dosyaların indirileceği dizinin mevcut olduğundan ve yazma izinlerine sahip olduğundan emin olun.
- İndirme çok büyükse, önceki denemeler başarısız olursa indirmeye devam etmek için bir yol uygulamak isteyebilirsiniz.
- İndirme işlemini yarıda kesmelerine izin verirseniz kullanıcılar minnettar olacaktır.
İndirme işleminin ayrıntılı kontrolüne ihtiyacınız yoksa, DownloadManager
yukarıda listelenen öğelerin çoğunu zaten ele aldığı için (3) 'ü kullanmayı düşünün .
Ancak ihtiyaçlarınızın değişebileceğini de düşünün. Örneğin, DownloadManager
hiçbir yanıt önbelleğe almaz . Aynı büyük dosyayı birden çok kez körü körüne indirir. Aslında bunu düzeltmenin kolay bir yolu yok. Eğer bir temel HttpURLConnection
(1, 2) ile başlarsanız , tek ihtiyacınız olan bir HttpResponseCache
. Dolayısıyla, temel, standart araçları öğrenme konusundaki ilk çaba iyi bir yatırım olabilir.
Bu sınıf API 26 düzeyinde kullanımdan kaldırılmıştır. ProgressDialog, kullanıcının uygulama ile etkileşimini engelleyen kalıcı bir iletişim kutusudur. Bu sınıfı kullanmak yerine, uygulamanızın kullanıcı arayüzüne yerleştirilebilen ProgressBar gibi bir ilerleme göstergesi kullanmalısınız. Alternatif olarak, kullanıcıyı görevin ilerleme durumu hakkında bilgilendirmek için bir bildirim kullanabilirsiniz. Daha fazla bilgi için Link