web-dev-qa-db-ja.com

アクティビティ内のダウンロードマネージャーの進行状況を表示する

アクティビティ内でダウンロードマネージャークラスを使用してダウンロードを実行しました。それは正常に機能し、次のタスクは、アクティビティ内で同じ進行率を表示することです。どうすればいいのかわかりません。

これまでの私のコード

public class DownloadSampleBook extends Activity{

private long enqueue;
private DownloadManager dm;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sample_download);

    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
                long downloadId = intent.getLongExtra(
                        DownloadManager.EXTRA_DOWNLOAD_ID, 0);
                Query query = new Query();
                query.setFilterById(enqueue);
                Cursor c = dm.query(query);
                if (c.moveToFirst()) {
                    int columnIndex = c
                            .getColumnIndex(DownloadManager.COLUMN_STATUS);
                    if (DownloadManager.STATUS_SUCCESSFUL == c
                            .getInt(columnIndex)) {

                       view.setImageURI(Uri.parse(uriString));
                    }
                }
            }
        }
    };

    registerReceiver(receiver, new IntentFilter(
            DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}

public void onClick(View view) {
    dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
    Request request = new Request(
            Uri.parse("http://abc.com/a.png"));
    enqueue = dm.enqueue(request);

}

public void showDownload(View view) {
    Intent i = new Intent();
    i.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS);
    startActivity(i);
}
}

進行状況のダウンロード率を与える方法はありますか?

18
Aman Virk

進捗状況の更新についてDownloadManagerにクエリを実行するタイミングを決定する適切な方法を探している場合は、URI content://downloads/my_downloadsContentObserverを登録することを検討してください。

例:

DownloadManager manager = (DownloadManager) getSystemService( Context.DOWNLOAD_SERVICE );
manager.enqueue( myRequest );

Uri myDownloads = Uri.parse( "content://downloads/my_downloads" );
getContentResolver().registerContentObserver( myDownloads, true, new DownloadObserver() );

...

public static class DownloadObserver extends ContentObserver {
   @Override
   public void onChange( boolean selfChange, Uri uri ) {
      Log.d( "DownloadObserver", "Download " + uri + " updated" );
   }

これにより、長時間実行されるダウンロードの各チャンクが受信されると、次の出力が生成されます。

D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated
D/DownloadObserver(15584): Download content://downloads/my_downloads/437 updated

ここで、「437」はダウンロードのIDです。

これは、クラスAndroid.provider.Downloadsで定義されたコンテンツURIに従うことに注意してください。これは、フレームワークに隠されているように見え、すべてのデバイスで一貫して機能するとは限りません。 ( https://Android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/Java/Android/provider/Downloads.Java#89

21
Dennis

サンプルコードでステータスを照会したのとほぼ同じ方法で、queryメソッドを使用して、これまでにダウンロードされたバイト数とダウンロードする必要のある合計バイト数を照会できます。これらの値を取得したら、進行状況をパーセンテージで計算するのはかなり簡単です。

新しいデータを受信したときに通知を受け取る方法はないようです。そのため、定期的にダウンロードマネージャーをポーリングして、監視するダウンロードの現在のステータスを確認する必要があります。

Query query = new Query();
query.setfilterById(downloadId);

Cursor c = dm.query(query);
if (c.moveToFirst()) {
  int sizeIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
  int downloadedIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
  long size = c.getInt(sizeIndex);
  long downloaded = c.getInt(downloadedIndex);
  double progress = 0.0;
  if (size != -1) progress = downloaded*100.0/size;  
  // At this point you have the progress as a percentage.
}

合計サイズは最初は-1であり、ダウンロードが開始された後にのみ入力されることに注意してください。したがって、上記のサンプルコードでは、-1をチェックし、サイズがまだ設定されていない場合は進行状況を0に設定しました。

ただし、場合によっては、合計サイズが返されないことがあります(たとえば、HTTPチャンク転送では、サイズを決定できるContent-Lengthヘッダーがありません)。この種のサーバーをサポートする必要がある場合は、ゼロのままになっているプログレスバーだけでなく、ダウンロードが進行中であることをユーザーに示す必要があります。

18

複数のファイルのダウンロードを追跡する必要がありました。たくさん考えて実験した後、私は次のコードを思いつきました。

private void startDownloadThread(final List<DownloadFile> list) {

        // Initializing the broadcast receiver ...
        mBroadCastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                mFinishedFilesFromNotif.add(intent.getExtras()
                        .getLong(DownloadManager.EXTRA_DOWNLOAD_ID));
            }
        };

        IntentFilter intentFilter = new IntentFilter(
                "Android.intent.action.DOWNLOAD_COMPLETE");
        DownloadProgressUIFragment.this.getActivity().registerReceiver(mBroadCastReceiver,
                intentFilter);

        // initializing the download manager instance ....
        mDownloadManager = (DownloadManager) getActivity()
                .getSystemService(Context.DOWNLOAD_SERVICE);

        // adding files to the download manager list ...
        for(DownloadFile f: list) {
            mDownloadIds.add(FileUtils.addFileForDownloadInBkg(getApplicationContext(),
                    f.getUrl(),
                    f.getPath()));
        }

        // starting the thread to track the progress of the download ..
        mProgressThread = new Thread(new Runnable() {
            @Override
            public void run() {

                // Preparing the query for the download manager ...
                DownloadManager.Query q = new DownloadManager.Query();
                long[] ids = new long[mDownloadIds.size()];
                final List<Long> idsArrList= new ArrayList<>();
                int i = 0;
                for (Long id: mDownloadIds) {
                    ids[i++] = id;
                    idsArrList.add(id);
                }
                q.setFilterById(ids);

                // getting the total size of the data ...
                Cursor c;

                while(true) {

                    // check if the downloads are already completed ...
                    // Here I have created a set of download ids from download manager to keep
                    // track of all the files that are dowloaded, which I populate by creating
                    //
                    if(mFinishedFilesFromNotif.containsAll(idsArrList)) {
                        isDownloadSuccess = true;

                        // TODO - Take appropriate action. Download is finished successfully
                        return;
                    }

                    // start iterating and noting progress ..
                    c = mDownloadManager.query(q);
                    if(c != null) {
                        int filesDownloaded = 0;
                        float fileFracs = 0f; // this stores the fraction of all the files in
                        // download
                        final int columnTotalSize = c.getColumnIndex
                                (DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
                        final int columnStatus = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
                        //final int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
                        final int columnDwnldSoFar =
                                c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);

                        while (c.moveToNext()) {
                            // checking the progress ..
                            if(c.getInt(columnStatus) == DownloadManager.STATUS_SUCCESSFUL) {
                                filesDownloaded++;
                            }
                            // If the file is partially downloaded, take its fraction ..
                            else if(c.getInt(columnTotalSize) > 0) {
                                fileFracs += ((c.getInt(columnDwnldSoFar) * 1.0f) /
                                        c.getInt(columnTotalSize));
                            } else if(c.getInt(columnStatus) == DownloadManager.STATUS_FAILED) {
                                // TODO - Take appropriate action. Error in downloading one of the
                                // files.
                                return;
                            }
                        }

                        c.close();

                        // calculate the progress to show ...
                        float progress = (filesDownloaded + fileFracs)/ids.length;

                        // setting the progress text and bar...
                        final int percentage = Math.round(progress * 100.0f);
                        final String txt = "Loading ... " + percentage + "%";

                        // Show the progress appropriately ...
                    }
                }
            }
        });

        mProgressThread.start();
    }

そして、ファイルにエンキューする機能は次のとおりです。

public static long addFileForDownloadInBkg(Context context, String url, String savePath) {
        Uri uri = Uri.parse(url);
        DownloadManager.Request request = new DownloadManager.Request(uri);
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        request.setDestinationUri(Uri.fromFile(new File(savePath)));

        final DownloadManager m = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        return m.enqueue(request);
    }

基本的に、ダウンロードが終了したファイルごとに個別に通知を受け取り、それらをセットに追加します。これは、基本的に、すべてのダウンロードが終了したかどうかを判断するのに役立つセットです。ファイルの数と完了したファイルの割合に基づいて進行状況を追跡します。これがお役に立てば幸いです。

3
Swapnil