Android ile bir dosya indirin ve ilerleme durumunu ProgressDialog'da gösterin


1046

Güncelleniyor basit bir uygulama yazmaya çalışıyorum. Bunun için ben bir dosya indirmek ve basit bir işlevi gerek şimdiki ilerlemeyi göstermek bir yer ProgressDialog. Nasıl yapılacağını biliyorum ProgressDialog, ancak mevcut ilerlemeyi nasıl görüntüleyeceğimi ve dosyayı nasıl indireceğinizi bilmiyorum .


2
Umarım aşağıdaki bağlantı size yardımcı olabilir ... androidhive.info/2012/04/…
Ganesh Katikar

1
Hızlı düzeltme için bu cevaba bakınız
Richa

Yanıtlar:


1873

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. AsyncTaskBir 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 onProgressUpdateve 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: ResultReceiverve IntentService. ResultReceiveriş 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 IntentServicebir alt Servicesınıftır ( Serviceuygulamanı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 ResultReceiveroynamaya 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 veResultReceiveryukarı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.

2.2 https://github.com/koush/ion adresini kullanın

3. DownloadManagerSınıfı kullanın ( GingerBreadve yalnızca daha yenisini)

GingerBread, DownloadManagerdosyaları 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. DownloadManagerKullanı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 ( INTERNETve WRITE_EXTERNAL_STORAGE) sahip olduğunuzdan emin olun ; Ayrıca ACCESS_NETWORK_STATEinternet 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, DownloadManageryukarı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


8
DownloadManager, işletim sisteminin bir parçasıdır, yani her zaman GB + 'da kullanılabilir ve kaldırılamaz.
Cristian

17
Cristian'in cevabında bir sorun var. Çünkü kod " 1. AsyncTask kullanın ve bir iletişim kutusunda indirme ilerleme durumunu gösterir " connection.connect (); daha sonra InputStream input = new BufferedInputStream (url.openStream ()); kodu sunucuya 2 bağlantı kurar. Aşağıdaki gibi kodu güncelleyerek bu davranışı değiştirmeyi başardık InputStream input = new BufferedInputStream (connection.getInputStream ());
nLL

99
Keşke android belgeleri bu özlü oldu.
Lou Morda

12
İçin önerilen close()akımlar ( inputve outputiçinde) finallyyerine tryherhangi bir istisna önce atılır aksi takdirde close(), size kapanmamış akışları takılmak var.
Pang

32
Bunun yerine sabit kod sdcard/kullanmayın / kullanmayın Environment.getExternalStorageDirectory().
Nima G

106

İnternetten bir şeyler indirecekseniz manifest dosyanıza izinler eklemeyi unutmayın!

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloandroid"
    android:versionCode="1"
    android:versionName="1.0">

        <uses-sdk android:minSdkVersion="10" />

        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <uses-permission android:name="android.permission.INTERNET"></uses-permission>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>

        <application 
            android:icon="@drawable/icon" 
            android:label="@string/app_name" 
            android:debuggable="true">

        </application>

</manifest>

1
Eminim ki READ_PHONE_STATE'e ihtiyacınız yok ve kesinlikle WRITE_EXTERNAL_STORAGE; Depolama Erişim Çerçevesi kullanılarak önlenebilecek tehlikeli bir izintir.
Monica'yı

32

Evet size güncelliyoruz Yukarıdaki kod .ama çalışacak progressbarin onProgressUpdateiçinde Asynctask ve geri düğmesine basın veya etkinlik bitirmek AsyncTaskgöreceksiniz indirme arka planda çalışırken bile, etkinlik geri döndüğünüzde UI .ve ile izini kaybeder ilerleme çubuğunda güncelleme yok. Bu nedenle, ur'u çalışan arka plandan güncellenen değerlerle güncelleyen bir zamanlayıcı görevi OnResume()gibi bir iş parçacığı çalıştırmayı deneyin .runOnUIThreadprogressbarAsyncTask

private void updateProgressBar(){
    Runnable runnable = new updateProgress();
    background = new Thread(runnable);
    background.start();
}

public class updateProgress implements Runnable {
    public void run() {
        while(Thread.currentThread()==background)
            //while (!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(1000); 
                Message msg = new Message();
                progress = getProgressPercentage();        
                handler.sendMessage(msg);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (Exception e) {
        }
    }
}

private Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        progress.setProgress(msg.what);
    }
};

Ur etkinliği görünmediğinde iş parçacığını yok etmeyi unutmayın .

private void destroyRunningThreads() {
    if (background != null) {
        background.interrupt();
        background=null;
    }
}

1
Bu benim sorunum. İlerleme çubuğunu güncellemek için bir zamanlayıcı görevinin nasıl yapılacağını söyleyebilir misiniz? Geride çalışan AsyncTask'tan değerler nasıl güncellenir
user1417127

2
okk değerlerini asynctask'den güncellemek için global veya statik bir değişken alır ... veya u güvenli taraf için DataBase'e ekleyebilir .. böylece kapanış uygulaması engellenmeyecektir .. Ve u ur güncellemek istediğiniz aktiviteyi yeniden başlattığınızda UI UI iş parçacığını çalıştırıyor ... Aşağıdaki örneğe bakınız
sheetal

UI yeni bir referans olmalı .. Benim durumumda yeni initalized ProgressBar gibi
sheetal

@sheetal, Ama Kodunuz olmadan iyi çalışıyor! Neden?! Cihazım Android 4.0.4 ile Xperia P. OnPreExecute true olarak ayarlar ve onPostExecute false olarak ayarlar bir statik boolean değişken tanımladım. İndirdiğimizi veya indirmediğimizi gösterir, böylece değişkenin true değerine eşit olup olmadığını kontrol edebilir, önceki ilerleme çubuğu iletişim kutusunu gösterebiliriz.
Behzad

@sheetal kodunuz biraz belirsiz, bana biraz tavsiye verebilir misiniz?
iSun

17

Benim Projesi kullanmak tavsiye ederim Netroid , O dayanıyor Volley . Ben çok olayları geri arama, dosya indirme yönetimi gibi bazı özellikler ekledim. Bu biraz yardımcı olabilir.


2
Birden fazla dosya indirmeyi destekliyor mu? Kullanıcının zamanlanmış indirmesini sağlayan bir proje üzerinde çalışıyorum. Belirli bir zamanda (örneğin, 12:00), hizmet kullanıcının daha önce seçtiği tüm bağlantıyı indirir. İhtiyacım olan hizmet, indirme bağlantılarını sıraya alabilmeli ve daha sonra hepsini indirebilmelidir (tek tek veya paralel, kullanıcıya bağlıdır). Teşekkür ederim
Hoang Trinh

@piavgh evet, istediğiniz tek şey tatmin oldu, benim örnek apk ödeme yapabilirsiniz, bir dosya indirme yönetimi demo dahil.
VinceStyling

Harika kütüphane! HTTPS Url's içerik indirmeyle ilgili sorunlar yaşıyor olmama rağmen iyi çalışıyor, sanki bir kendi SSLSocketFactoryeklemenizi ayarlayabilir HostnameVerifierve mümkün değil ve böyle bir doğrulayıcıya ihtiyacım var. Bununla ilgili bir sorun yarattı .
DarkCygnus

Volley için bağlantı . -> Bulunamadı
Rumit Patel

14

Ben aynı bağlamda AsyncTaskoluşturma işlemek için sınıf değiştirdik. progressDialogAşağıdaki kod daha yeniden kullanılabilir olacağını düşünüyorum. (herhangi bir aktiviteden sadece bağlam, hedef Dosya, iletişim mesajı iletilebilir)

public static class DownloadTask extends AsyncTask<String, Integer, String> {
    private ProgressDialog mPDialog;
    private Context mContext;
    private PowerManager.WakeLock mWakeLock;
    private File mTargetFile;
    //Constructor parameters :
    // @context (current Activity)
    // @targetFile (File object to write,it will be overwritten if exist)
    // @dialogMessage (message of the ProgresDialog)
    public DownloadTask(Context context,File targetFile,String dialogMessage) {
        this.mContext = context;
        this.mTargetFile = targetFile;
        mPDialog = new ProgressDialog(context);

        mPDialog.setMessage(dialogMessage);
        mPDialog.setIndeterminate(true);
        mPDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mPDialog.setCancelable(true);
        // reference to instance to use inside listener
        final DownloadTask me = this;
        mPDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                me.cancel(true);
            }
        });
        Log.i("DownloadTask","Constructor done");
    }

    @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();
            }
            Log.i("DownloadTask","Response " + connection.getResponseCode());

            // 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(mTargetFile,false);

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    Log.i("DownloadTask","Cancelled");
                    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;
    }
    @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) mContext.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                getClass().getName());
        mWakeLock.acquire();

        mPDialog.show();

    }

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

    }

    @Override
    protected void onPostExecute(String result) {
        Log.i("DownloadTask", "Work Done! PostExecute");
        mWakeLock.release();
        mPDialog.dismiss();
        if (result != null)
            Toast.makeText(mContext,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(mContext,"File Downloaded", Toast.LENGTH_SHORT).show();
    }
}

Uyanma kilidi izni eklemeyi unutma <kullanır-izin android: name = "android.permission.WAKE_LOCK" />
Hitesh Sahu

8

"/ Sdcard ..." yerine yeni File ("/ mnt / sdcard / ...") yazmayı unutmayın, aksi takdirde bir FileNotFoundException alırsınız


Bölüm 2 Hizmetten indirme İlerleme durumu iletişim kutusu ilerleme artışını görüntüleyemiyor. doğrudan 100 dönüş, eğer 100 doğrudan setprogress 100 kontrol ve ilerleme, nasıl ilerleme artırmak için ?? sadece 0 ilerleme görüntüler ama aslında indir çalışan
Nirav Mehta

diğer 100 işten sadece%
0'ını

14
Bunu yapma! Environment.getExternalStorageDirectory().getAbsolutePath()Sdcard yol almak için var . Harici depolama biriminin takılı olup olmadığını da kontrol etmeyi unutmayın - Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)( Mannaz )
naXa

8

Ben bu blog yazısı çok yararlı buldum , Dosya indirmek için loopJ kullanarak, sadece bir Basit işlevi vardır, bazı yeni android çocuklar için yararlı olacaktır.


7

Android geliştirmeyi öğrenmeye başlarken ProgressDialog, bunun yolunun olduğunu öğrendim . Dosya indirilirken ilerleme düzeyini güncellemek için bir setProgressyöntem ProgressDialogçağrılabilir.

Birçok uygulamada gördüğüm en iyi şey, ilerleme iletişim kutusuna stok sürümünden daha iyi bir görünüm ve his vermek için bu ilerleme iletişim kutusunun özelliklerini özelleştirmeleridir. Kullanıcıyı kurbağa, fil veya sevimli kediler / köpek yavruları gibi animasyonlarla tutmak iyi. İlerleme iletişim kutusundaki herhangi bir animasyon kullanıcıları çeker ve uzun süre bekletilmek istemezler.



5

Kişisel tavsiyem, ilerleme durumu iletişim kutusunun yatay ilerleme çubuğu stilini kullanırsanız İlerleme İletişim Kutusunu kullanmak ve yürütmeden önce OnPreExecute()derlemek veya ilerlemeye başlamaktır . Kalan kısım ise algoritmasını optimize etmektir doInBackground.


5

Android Query kitaplığını kullanın, gerçekten çok havalı.Diğer ProgressDialogörneklerde gördüğünüz gibi kullanmak için değiştirebilirsiniz , bu düzeninizdeki ilerleme görünümünü gösterecek ve tamamlandıktan sonra gizleyecektir.

File target = new File(new File(Environment.getExternalStorageDirectory(), "ApplicationName"), "tmp.pdf");
new AQuery(this).progress(R.id.progress_view).download(_competition.qualificationScoreCardsPdf(), target, new AjaxCallback<File>() {
    public void callback(String url, File file, AjaxStatus status) {
        if (file != null) {
            // do something with file  
        } 
    }
});

Mesele şu ki, kullanmayı bıraktım, çünkü onun bakımsız, bu yüzden artık iyi bir cevap olduğunu düşünmeyin.
Renetik

3

Android Query sağlıklı kalmak için çok büyük ve bakımsız olduğu için şu anda kullandığım diğer çözümlere başka bir cevap ekliyorum. Ben de bu https://github.com/amitshekhariitbhu/Fast-Android-Networking adresine taşındım .

    AndroidNetworking.download(url,dirPath,fileName).build()
      .setDownloadProgressListener(new DownloadProgressListener() {
        public void onProgress(long bytesDownloaded, long totalBytes) {
            bar.setMax((int) totalBytes);
            bar.setProgress((int) bytesDownloaded);
        }
    }).startDownload(new DownloadListener() {
        public void onDownloadComplete() {
            ...
        }

        public void onError(ANError error) {
            ...
        }
    });

2

İzinler

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

HttpURLConnection kullanma

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class DownloadFileUseHttpURLConnection extends Activity {

ProgressBar pb;
Dialog dialog;
int downloadedSize = 0;
int totalSize = 0;
TextView cur_val;
String dwnload_file_path =  
"http://coderzheaven.com/sample_folder/sample_file.png";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Button b = (Button) findViewById(R.id.b1);
    b.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
             showProgress(dwnload_file_path);

                new Thread(new Runnable() {
                    public void run() {
                         downloadFile();
                    }
                  }).start();
        }
    });
}

void downloadFile(){

    try {
        URL url = new URL(dwnload_file_path);
        HttpURLConnection urlConnection = (HttpURLConnection)   
 url.openConnection();

        urlConnection.setRequestMethod("GET");
        urlConnection.setDoOutput(true);

        //connect
        urlConnection.connect();

        //set the path where we want to save the file           
        File SDCardRoot = Environment.getExternalStorageDirectory(); 
        //create a new file, to save the downloaded file 
        File file = new File(SDCardRoot,"downloaded_file.png");

        FileOutputStream fileOutput = new FileOutputStream(file);

        //Stream used for reading the data from the internet
        InputStream inputStream = urlConnection.getInputStream();

        //this is the total size of the file which we are downloading
        totalSize = urlConnection.getContentLength();

        runOnUiThread(new Runnable() {
            public void run() {
                pb.setMax(totalSize);
            }               
        });

        //create a buffer...
        byte[] buffer = new byte[1024];
        int bufferLength = 0;

        while ( (bufferLength = inputStream.read(buffer)) > 0 ) {
            fileOutput.write(buffer, 0, bufferLength);
            downloadedSize += bufferLength;
            // update the progressbar //
            runOnUiThread(new Runnable() {
                public void run() {
                    pb.setProgress(downloadedSize);
                    float per = ((float)downloadedSize/totalSize) *     
                    100;
                    cur_val.setText("Downloaded " + downloadedSize +  

                    "KB / " + totalSize + "KB (" + (int)per + "%)" );
                }
            });
        }
        //close the output stream when complete //
        fileOutput.close();
        runOnUiThread(new Runnable() {
            public void run() {
                // pb.dismiss(); // if you want close it..
            }
        });         

    } catch (final MalformedURLException e) {
        showError("Error : MalformedURLException " + e);        
        e.printStackTrace();
    } catch (final IOException e) {
        showError("Error : IOException " + e);          
        e.printStackTrace();
    }
    catch (final Exception e) {
        showError("Error : Please check your internet connection " +  
e);
    }       
}

void showError(final String err){
    runOnUiThread(new Runnable() {
        public void run() {
            Toast.makeText(DownloadFileDemo1.this, err,  
      Toast.LENGTH_LONG).show();
        }
    });
}

void showProgress(String file_path){
    dialog = new Dialog(DownloadFileDemo1.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setContentView(R.layout.myprogressdialog);
    dialog.setTitle("Download Progress");

    TextView text = (TextView) dialog.findViewById(R.id.tv1);
    text.setText("Downloading file from ... " + file_path);
    cur_val = (TextView) dialog.findViewById(R.id.cur_pg_tv);
    cur_val.setText("Starting download...");
    dialog.show();

     pb = (ProgressBar)dialog.findViewById(R.id.progress_bar);
     pb.setProgress(0);
            pb.setProgressDrawable(
      getResources().getDrawable(R.drawable.green_progress));  
  }
}

1

LiveData ve coroutines kullanarak indirme yöneticisinin ilerlemesini gözlemleyebilirsiniz, aşağıdaki özete bakın

https://gist.github.com/FhdAlotaibi/678eb1f4fa94475daf74ac491874fc0e

data class DownloadItem(val bytesDownloadedSoFar: Long = -1, val totalSizeBytes: Long = -1, val status: Int)

class DownloadProgressLiveData(private val application: Application, private val requestId: Long) : LiveData<DownloadItem>(), CoroutineScope {

    private val downloadManager by lazy {
        application.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
    }

    private val job = Job()

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.IO + job

    override fun onActive() {
        super.onActive()
        launch {
            while (isActive) {
                val query = DownloadManager.Query().setFilterById(requestId)
                val cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    Timber.d("Status $status")
                    when (status) {
                        DownloadManager.STATUS_SUCCESSFUL,
                        DownloadManager.STATUS_PENDING,
                        DownloadManager.STATUS_FAILED,
                        DownloadManager.STATUS_PAUSED -> postValue(DownloadItem(status = status))
                        else -> {
                            val bytesDownloadedSoFar = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                            val totalSizeBytes = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                            postValue(DownloadItem(bytesDownloadedSoFar.toLong(), totalSizeBytes.toLong(), status))
                        }
                    }
                    if (status == DownloadManager.STATUS_SUCCESSFUL || status == DownloadManager.STATUS_FAILED)
                        cancel()
                } else {
                    postValue(DownloadItem(status = DownloadManager.STATUS_FAILED))
                    cancel()
                }
                cursor.close()
                delay(300)
            }
        }
    }

    override fun onInactive() {
        super.onInactive()
        job.cancel()
    }

}

Bu sınıf için bir usecase örneği verebilir misiniz?
Karim Karimov


0

Kotlin'de dosya indirmek için yardımcı program ve çalışma yöneticisini kullanabiliriz.

Build.gradle dosyasına bağımlılık ekleme

    implementation "androidx.work:work-runtime-ktx:2.3.0-beta01"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.1"

WorkManager sınıfı

    import android.content.Context
    import android.os.Environment
    import androidx.work.CoroutineWorker
    import androidx.work.WorkerParameters
    import androidx.work.workDataOf
    import com.sa.chat.utils.Const.BASE_URL_IMAGE
    import com.sa.chat.utils.Constants
    import kotlinx.coroutines.delay
    import java.io.BufferedInputStream
    import java.io.File
    import java.io.FileOutputStream
    import java.net.URL

    class DownloadMediaWorkManager(appContext: Context, workerParams: WorkerParameters)
        : CoroutineWorker(appContext, workerParams) {

        companion object {
            const val WORK_TYPE = "WORK_TYPE"
            const val WORK_IN_PROGRESS = "WORK_IN_PROGRESS"
            const val WORK_PROGRESS_VALUE = "WORK_PROGRESS_VALUE"
        }

        override suspend fun doWork(): Result {

            val imageUrl = inputData.getString(Constants.WORK_DATA_MEDIA_URL)
            val imagePath = downloadMediaFromURL(imageUrl)

            return if (!imagePath.isNullOrEmpty()) {
                Result.success(workDataOf(Constants.WORK_DATA_MEDIA_URL to imagePath))
            } else {
                Result.failure()
            }
        }

        private suspend fun downloadMediaFromURL(imageUrl: String?): String? {

            val file = File(
                    getRootFile().path,
                    "IMG_${System.currentTimeMillis()}.jpeg"
            )

            val url = URL(BASE_URL_IMAGE + imageUrl)
            val connection = url.openConnection()
            connection.connect()

            val lengthOfFile = connection.contentLength
            // download the file
            val input = BufferedInputStream(url.openStream(), 8192)
            // Output stream
            val output = FileOutputStream(file)

            val data = ByteArray(1024)
            var total: Long = 0
            var last = 0

            while (true) {

                val count = input.read(data)
                if (count == -1) break
                total += count.toLong()

                val progress = (total * 100 / lengthOfFile).toInt()

                if (progress % 10 == 0) {
                    if (last != progress) {
                        setProgress(workDataOf(WORK_TYPE to WORK_IN_PROGRESS,
                                WORK_PROGRESS_VALUE to progress))
                    }
                    last = progress
                    delay(50)
                }
                output.write(data, 0, count)
            }

            output.flush()
            output.close()
            input.close()

            return file.path

        }

        private fun getRootFile(): File {

            val rootDir = File(Environment.getExternalStorageDirectory().absolutePath + "/AppName")

            if (!rootDir.exists()) {
                rootDir.mkdir()
            }

            val dir = File("$rootDir/${Constants.IMAGE_FOLDER}/")

            if (!dir.exists()) {
                dir.mkdir()
            }
            return File(dir.absolutePath)
        }
    }

Etkinlik sınıfındaki çalışma yöneticisi aracılığıyla indirmeye başlayın

 private fun downloadImage(imagePath: String?, id: String) {

            val data = workDataOf(WORK_DATA_MEDIA_URL to imagePath)
            val downloadImageWorkManager = OneTimeWorkRequestBuilder<DownloadMediaWorkManager>()
                    .setInputData(data)
                    .addTag(id)
                    .build()

            WorkManager.getInstance(this).enqueue(downloadImageWorkManager)

            WorkManager.getInstance(this).getWorkInfoByIdLiveData(downloadImageWorkManager.id)
                    .observe(this, Observer { workInfo ->

                        if (workInfo != null) {
                            when {
                                workInfo.state == WorkInfo.State.SUCCEEDED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.GONE
                                }
                                workInfo.state == WorkInfo.State.FAILED || workInfo.state == WorkInfo.State.CANCELLED || workInfo.state == WorkInfo.State.BLOCKED -> {
                                    progressBar?.visibility = View.GONE
                                    ivDownload?.visibility = View.VISIBLE
                                }
                                else -> {
                                    if(workInfo.progress.getString(WORK_TYPE) == WORK_IN_PROGRESS){
                                        val progress = workInfo.progress.getInt(WORK_PROGRESS_VALUE, 0)
                                        progressBar?.visibility = View.VISIBLE
                                        progressBar?.progress = progress
                                        ivDownload?.visibility = View.GONE

                                    }
                                }
                            }
                        }
                    })

        }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.