在活动中显示下载管理器进度

Posted

技术标签:

【中文标题】在活动中显示下载管理器进度【英文标题】:Show Download Manager progress inside activity 【发布时间】:2013-01-25 18:05:10 【问题描述】:

我在我的活动中使用了下载管理器类来执行下载;它工作正常,我的下一个任务是在我的活动中显示相同的进度百分比。我不知道该怎么做。

到目前为止我的代码

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);


有什么方法可以给出进度下载百分比吗?

【问题讨论】:

也想知道。没有明确的解决方案 【参考方案1】:

如果您正在寻找一种合适的方式来确定何时查询 DownloadManager 以获取进度更新,请考虑为 uri content://downloads/my_downloads 注册 ContentObserver

例子:

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)

【讨论】:

【参考方案2】:

您可以使用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 标头可以从中确定大小)。如果您需要支持这种服务器,您可能应该向用户提供某种指示下载正在进行中,而不仅仅是卡在零的进度条。

【讨论】:

不应该检查大小的零值吗?类似下载*100.0/(size == 0 ? 1 : size)【参考方案3】:

我需要跟踪多个文件的下载。经过大量的思考和实验,我想出了以下代码:

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);
    

基本上,我会针对已完成下载的每个文件单独收到通知,然后将它们添加到一个集合中,该集合基本上是帮助我确定所有下载是否已完成的集合。我根据文件的数量和每个文件完成的比例来跟踪进度。我希望这会有所帮助。

【讨论】:

嘿swapnil你能提供完整的源代码吗

以上是关于在活动中显示下载管理器进度的主要内容,如果未能解决你的问题,请参考以下文章

改进xutils下载管理器,使其,在随意地方进行进度更新,以及其它状态监听操作

Windows Server2008怎么使用照片查看器

在集合视图单元格 Swift 中管理多个进度视图

Android进度没有相应地工作

无法使用下载管理器在 android webview 中下载 excel

运行安装包后,不显示安装界面,但任务管理器显示有此进程,没有任何反应,怎么办?