DownloadManager(强制版本更新和源码分析)

ps:通常App更新是通过DownLoadManager来实现,更新方式分为强制升级(遇到重大bug时),自选是否版本升级。

DownLoadManager类:

  • 官方英文介绍:


    The download manager is a system service that handles long-running HTTP downloads.
    Clients may request that a URI be downloaded to a particular destination file.
    The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots.
    Instances of this class should be obtained through getSystemService(String) by passing DOWNLOAD_SERVICE.
    Apps that request downloads through this API should register a broadcast receiver for ACTION_NOTIFICATION_CLICKED to appropriately handle when the user clicks on a running download in a notification or from the downloads UI.
    Note that the application must have the INTERNET permission to use this class.

  • 中文翻译介绍:
    • 含义:
      DownLoadManager是一种长期执行http下载任务的系统服务(进程)。

    • 特性:
      客户端可以通过URI下载相对应文件,DownloadManager是运行在后台,关注http交互和重新下载(在失败或者链接改变和系统重启)

    • 使用方式:
      DownLoadManager对象=(DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE);

    • 使用权限: <uses-permission android:name="android.permission.INTERNET" />

  • 其常用的API:
    1. enqueue(DownloadManager.Request request) : 添加request,开启下载,返回下载的id(唯一的)

    2. remove(long… ids):根据id取消下载

    3. query(DownloadManager.Query query): 查询指定id(即指定request)的下载情况,返回一个cursor

    4. addCompletedDownload(String title, String description, boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification):
      添加一个file文件到下载的数据库系统,因此当前程序能够管理下载情况。简单来说,根据指定条件开启下载文件

    5. DownloadManager类的API :
      https://developer.android.com/reference/android/app/DownloadManager.html

  • 相关类:
    1. DownloadManager.Request

      • 其常用api:

        1. addRequestHeader(String header, String value):添加http的header

        2. setAllowedNetworkTypes(int flags):设置允许的网络类型

        3. setDestinationUri(Uri uri):自定义下载目录

        4. setNotificationVisibility(int visibility):设置Notification的显示情况

        5. setTitle(CharSequence title):设置notification中显示的标题

    2. DownloadManager.Query:

      • setFilterById(long… ids):添加下载的id,便于查询对应的下载情况
  • 使用案例之自选更新与强制更新APP版本:
    1. 思路分析:

      • App强制版本升级思路分析

      • 创建一个不可取消的dialog(按back键不能取消,按弹窗外不可取消)

      • 指定文件路径,通过DownloadManager开始下载

      • 查询下载情况,在dialog里中更新下载状态(handler回调主线程中,更新UI)

      • 下载完成后进行安装(静态注册广播接收器,实现安装功能)

      • 自选更新思路:借助系统的DownloadManager进行下载,Notifaction显示下载进度

    2. 在确定好更新版本需求后,设置Request:

      /**
       * 设置Request参数
       * @param url
       * @return
       */
      public DownloadManager.Request   CreateRequest(String url){
          DownloadManager.Request  request=new DownloadManager.Request(Uri.parse(url));
          switch (state){
              case  Constants.OPTIONAL://自选更新
                  request.setTitle("秒加");// 文件下载时显示的标题
                  request.setNotificationVisibility(   
                    DownloadManager.Request.VISIBILITY_VISIBLE);// 下载完成后,notification会自动消失
                  break;
              case Constants.FORCIBLEY://强制版本更新
               request.setNotificationVisibility(   
                   DownloadManager.Request.VISIBILITY_HIDDEN);// 隐藏notification
                  break;
          }
          File file=MyUtils.getCacheFile(Constants.APPNAME);
          if(file!=null&&file.exists()){
              file.delete();//删除掉存在的apk
          }
          request.setDestinationUri(Uri.fromFile(file));//指定apk缓存路径
          return  request;
      }
      • 在这里遇到个问题:

        // 若是使用VISIBILITY_HIDDEN,直接给报错:
        java.lang.SecurityException: Invalid value for visibility: 2
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
        at android.content.ContentProviderProxy.insert(ContentProviderNative.java:468)
        at android.content.ContentResolver.insert(ContentResolver.java:1190)
        at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185)
        at android.app.DownloadManager.enqueue(DownloadManager.java:1390)
        源码:public static final int VISIBILITY_HIDDEN = 2;  
      • 通过查看源码,找到解决方式:

         /**
         * Control whether a system notification is posted by the download manager while this
         * download is running. If enabled, the download manager posts notifications about downloads
         * through the system {@link android.app.NotificationManager}. By default, a notification is
         * shown.
         *
         * If set to false, this requires the permission
         * android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
         *
         * @param show whether the download manager should show a notification for this download.
         * @return this object
         * @deprecated use {@link #setNotificationVisibility(int)}
         */
        @Deprecated
        public Request setShowRunningNotification(boolean show) {
            return (show) ? setNotificationVisibility(VISIBILITY_VISIBLE) :
                    setNotificationVisibility(VISIBILITY_HIDDEN);
        }
        setShowRunningNotification()源码可知: 添加权限,<uses-permission    
        android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
    3. 通过DownLoadManager开始下载:

      /**
      * 通过DownloadManager开始下载
      * @return
      */
      public long  startDownload(){
           Context appContext=BaseApplication.getAppContext();
           DownloadManager downloadManager=(DownloadManager)   
                 appContext.getSystemService(Context.DOWNLOAD_SERVICE);
           long requestId= downloadManager.enqueue(CreateRequest(url));
           if(state==Constants.FORCIBLEY){//强制升级,显示自定义进度的弹窗
                   queryDownloadProgress(requestId,downloadManager);
           }
          return  requestId;
      }
    4. 异步线程中通过DownloadManager.Query查询下载进度,Handler回调更新UI(强制版本升级需这步,自选可以跳过)

      /**
      * 查询下载进度
      * @param requestId
      *
      * DownloadManager.COLUMN_TOTAL_SIZE_BYTES  下载文件的大小(总字节数)
      * DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR 当前下载文件的字节数
      */
      public void queryDownloadProgress(long requestId,DownloadManager  downloadManager){
          DownloadManager.Query query=new DownloadManager.Query();
          query.setFilterById(requestId);
          try {
              boolean isGoging=true;
              while (isGoging) {
                   Cursor cursor = downloadManager.query(query);
                   if (cursor != null && cursor.moveToFirst()) {
                   int state = cursor.getInt( 
                         cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
                   switch (state) {
                      case DownloadManager.STATUS_SUCCESSFUL://下载成功
                            isGoging=false;
                          handler.obtainMessage( 
                          downloadManager.STATUS_SUCCESSFUL).sendToTarget();//发送到主线程,更新ui
                          break;
                      case DownloadManager.STATUS_FAILED://下载失败
                          isGoging=false;
                          handler.obtainMessage(downloadManager.STATUS_FAILED).sendToTarget(); 
                           //发送到主线程,更新ui
                          break;
      
                      case DownloadManager.STATUS_RUNNING://下载中
                          /**
                           * 计算下载下载率;
                           */
                          int totalSize = cursor.getInt( 
                             cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                          int currentSize = cursor.getInt(  cursor.getColumnIndex(    
                                   DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                          int progress = (int) (((float) currentSize) /  
                                                                ((float) totalSize) * 100);
                          handler.obtainMessage(downloadManager.STATUS_RUNNING,  、
                                 progress).sendToTarget();//发送到主线程,更新ui
                          break;
      
                      case DownloadManager.STATUS_PAUSED://下载停止
                          handler.obtainMessage(DownloadManager.STATUS_PAUSED).sendToTarget();
                          break;
      
                      case DownloadManager.STATUS_PENDING://准备下载
                          handler.obtainMessage(DownloadManager.STATUS_PENDING).sendToTarget();
                          break;
                  }
              }
              if(cursor!=null){
                  cursor.close();
              }
          }
      
        }catch (Exception e){
          e.printStackTrace();
        }
      } 
      /*handler更新ui*/
      private Handler handler = new Handler(new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
          switch (msg.what) {
              case DownloadManager.STATUS_SUCCESSFUL:
                  downloadDialog.setProgress(100);
                  cancleDialog();
      
                  break;
              case DownloadManager.STATUS_RUNNING:
                  downloadDialog.setProgress((int) msg.obj);
                  break;
              case DownloadManager.STATUS_FAILED:
                  cancleDialog();
                  break;
              case DownloadManager.STATUS_PENDING:
                  showDialog();
                  break;
          }
          return false;
      }
      });
    5. 注册监听BroadcasetReceiver,监听下载完成后进行安装:

      <receiver android:name=".InstallAPk_BroadcastReceiver">
          <intent-filter>
              <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
          </intent-filter>
      </receiver>
      
      public class InstallAPk_BroadcastReceiver extends BroadcastReceiver{
           @Override
           public void onReceive(Context context, Intent intent) {
                     install(context);
            }
      
           public void install(Context context){
                  File file = MyUtils.getCacheFile(Constants.APPNAME);
                  if (file == null || !file.exists()) {
                        return;
                   }
                   Intent installintent = new Intent();
                   installintent.setAction(Intent.ACTION_VIEW);
              // 在Boradcast中启动活动需要添加Intent.FLAG_ACTIVITY_NEW_TASK
                  installintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                  installintent.setDataAndType(Uri.fromFile(file),
                         "application/vnd.android.package-archive");
                  context.startActivity(installintent);
         }
      }
    6. 效果图如下:

      • 强制版本更新效果图:

      • 自选版本更新效果图:
        这里写图片描述

    项目下载链接: http://download.csdn.net/detail/hexingen/9609609

  • 源码分析:

    DownLoadManager中包含三个静态类和一些通过DownLoadProvider操作数据库的api,它采用了观察者模式,实现自动调配功能。

    1. DownloadManager.Request类的源码分析

      1.这类包含全部信息,唯一需求的参数URI
      2.最好自定义下载路径,防止被系统
      
      public static class Request {
         //手机网络标志
          public static final int NETWORK_MOBILE = 1 << 0;
      
         //wifi网络标志
          public static final int NETWORK_WIFI = 1 << 1;
      
          //bluetootch标志
          public static final int NETWORK_BLUETOOTH = 1 << 2;
      
          private Uri mUri;
          private Uri mDestinationUri;
          private List<Pair<String, String>> mRequestHeaders = new ArrayList<Pair<String, String>>();
          private CharSequence mTitle;
          private CharSequence mDescription;
          private String mMimeType;
          private int mAllowedNetworkTypes = ~0; 
          private boolean mRoamingAllowed = true;
          private boolean mMeteredAllowed = true;
          private boolean mIsVisibleInDownloadsUi = true;
          private boolean mScannable = false;
          private boolean mUseSystemCache = false;
      
         //可以被媒体扫描的文件,对应存在数据库中列
          private static final int SCANNABLE_VALUE_YES = 0;
      
          //私有文件(不被媒体扫描到),对应在数据库中列
          private static final int SCANNABLE_VALUE_NO = 2;
      
          //显示在下载的通知,下载完后消失
          public static final int VISIBILITY_VISIBLE = 0;
      
         //下载时显示通知,完成通知
          public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
      
          //不显示下载通知
          public static final int VISIBILITY_HIDDEN = 2;
      
          //下载完后显示通知
          public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3;
      
           //默认显示哪种通知
          private int mNotificationVisibility = VISIBILITY_VISIBLE;
      
          //添加uri
          public Request(Uri uri) {
              if (uri == null) {
                  throw new NullPointerException();
              }
              String scheme = uri.getScheme();
              if (scheme == null || (!scheme.equals("http") && !scheme.equals("https"))) {
                  throw new IllegalArgumentException("Can only download HTTP/HTTPS URIs: " + uri);
              }
              mUri = uri;
          }
      
          Request(String uriString) {
              mUri = Uri.parse(uriString);
          }
      
          //自定下载文件路径
          public Request setDestinationUri(Uri uri) {
              mDestinationUri = uri;
              return this;
          }
      
          //设置系统下载缓存到自定义目录中,适合系统权限的应用
          public Request setDestinationToSystemCache() {
              mUseSystemCache = true;
              return this;
          }
      
         //自定义不被媒体扫描的sdcard文件路径
          public Request setDestinationInExternalFilesDir(Context context, String dirType,
                  String subPath) {
              final File file = context.getExternalFilesDir(dirType);
              if (file == null) {
                  throw new IllegalStateException("Failed to get external storage files directory");
              } else if (file.exists()) {
                  if (!file.isDirectory()) {
                      throw new IllegalStateException(file.getAbsolutePath() +
                              " already exists and is not a directory");
                  }
              } else {
                  if (!file.mkdirs()) {
                      throw new IllegalStateException("Unable to create directory: "+
                              file.getAbsolutePath());
                  }
              }
              setDestinationFromBase(file, subPath);
              return this;
          }
      
          //设置自定义的公共sdcard文件路径,可以被媒体扫描到
          public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
              File file = Environment.getExternalStoragePublicDirectory(dirType);
              if (file == null) {
                  throw new IllegalStateException("Failed to get external storage public directory");
              } else if (file.exists()) {
                  if (!file.isDirectory()) {
                      throw new IllegalStateException(file.getAbsolutePath() +
                              " already exists and is not a directory");
                  }
              } else {
                  if (!file.mkdirs()) {
                      throw new IllegalStateException("Unable to create directory: "+
                              file.getAbsolutePath());
                  }
              }
              setDestinationFromBase(file, subPath);
              return this;
          }
      
          private void setDestinationFromBase(File base, String subPath) {
              if (subPath == null) {
                  throw new NullPointerException("subPath cannot be null");
              }
              mDestinationUri = Uri.withAppendedPath(Uri.fromFile(base), subPath);
          }
      
          //若是文件是可以被媒体扫描,在enqueue()前调用
          public void allowScanningByMediaScanner() {
              mScannable = true;
          }
      
          //添加header
          public Request addRequestHeader(String header, String value) {
              if (header == null) {
                  throw new NullPointerException("header cannot be null");
              }
              if (header.contains(":")) {
                  throw new IllegalArgumentException("header may not contain ':'");
              }
              if (value == null) {
                  value = "";
              }
              mRequestHeaders.add(Pair.create(header, value));
              return this;
          }
      
         //设置Notification的显示标题
          public Request setTitle(CharSequence title) {
              mTitle = title;
              return this;
          }
      
          //设置显示在notification中内容
          public Request setDescription(CharSequence description) {
              mDescription = description;
              return this;
          }
      
          //设置下载的文件类型
          public Request setMimeType(String mimeType) {
              mMimeType = mimeType;
              return this;
          }
          //setNotificationVisibility()所取代
          @Deprecated
          public Request setShowRunningNotification(boolean show) {
              return (show) ? setNotificationVisibility(VISIBILITY_VISIBLE) :
                      setNotificationVisibility(VISIBILITY_HIDDEN);
          }
      
          //设置Notification得使用
          public Request setNotificationVisibility(int visibility) {
              mNotificationVisibility = visibility;
              return this;
          }
      
           //设置允许下载的网络类型
          public Request setAllowedNetworkTypes(int flags) {
              mAllowedNetworkTypes = flags;
              return this;
          }
      
         //设置是否可以漫游状态网络连接,默认true
          public Request setAllowedOverRoaming(boolean allowed) {
              mRoamingAllowed = allowed;
              return this;
          }
      
      
      //设置是否可以计量网络连接,默然true
          public Request setAllowedOverMetered(boolean allow) {
              mMeteredAllowed = allow;
              return this;
          }
      
           //设置下载Uri是否可见
          public Request setVisibleInDownloadsUi(boolean isVisible) {
              mIsVisibleInDownloadsUi = isVisible;
              return this;
          }
      
          //获取到Request中信息,在系统下载对应的数据库insert
          ContentValues toContentValues(String packageName) {
              ContentValues values = new ContentValues();
              assert mUri != null;
              values.put(Downloads.Impl.COLUMN_URI, mUri.toString());
              values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true);
              values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, packageName);
      
              if (mDestinationUri != null) {
                  values.put(Downloads.Impl.COLUMN_DESTINATION,  
                  Downloads.Impl.DESTINATION_FILE_URI);
                  values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, mDestinationUri.toString());
              } else {
                  values.put(Downloads.Impl.COLUMN_DESTINATION,
                             (this.mUseSystemCache) ?
                                     Downloads.Impl.DESTINATION_SYSTEMCACHE_PARTITION :
      
                                  Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
              }
              // is the file supposed to be media-scannable?
              values.put(Downloads.Impl.COLUMN_MEDIA_SCANNED, (mScannable) ? SCANNABLE_VALUE_YES   :SCANNABLE_VALUE_NO);
      
              if (!mRequestHeaders.isEmpty()) {
                  encodeHttpHeaders(values);
              }
      
              putIfNonNull(values, Downloads.Impl.COLUMN_TITLE, mTitle);
              putIfNonNull(values, Downloads.Impl.COLUMN_DESCRIPTION, mDescription);
              putIfNonNull(values, Downloads.Impl.COLUMN_MIME_TYPE, mMimeType);
      
              values.put(Downloads.Impl.COLUMN_VISIBILITY, mNotificationVisibility);
              values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES 
                  , mAllowedNetworkTypes);
              values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
              values.put(Downloads.Impl.COLUMN_ALLOW_METERED, mMeteredAllowed);
              values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI 
                  , mIsVisibleInDownloadsUi);
      
              return values;
          }
      
          private void encodeHttpHeaders(ContentValues values) {
              int index = 0;
              for (Pair<String, String> header : mRequestHeaders) {
                  String headerString = header.first + ": " + header.second;
                  values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + index 
                  , headerString);
                  index++;
              }
          }
      
          private void putIfNonNull(ContentValues contentValues, String key, Object value) {
              if (value != null) {
                  contentValues.put(key, value.toString());
              }
          }
      }
    2. DownloadManager.Query类的源码:

      本类:用于筛选指定条件的下载
      public static class Query {
      //上升排序
      public static final int ORDER_ASCENDING = 1;
      
      //降序
      public static final int ORDER_DESCENDING = 2;
      
      private long[] mIds = null;
      private Integer mStatusFlags = null;
      private String mOrderByColumn = Downloads.Impl.COLUMN_LAST_MODIFICATION;
      private int mOrderDirection = ORDER_DESCENDING;
      private boolean mOnlyIncludeVisibleInDownloadsUi = false;
      
      //给定下载id
      public Query setFilterById(long... ids) {
          mIds = ids;
          return this;
      }
      
      //返回匹配到的下载状态的Query
      public Query setFilterByStatus(int flags) {
          mStatusFlags = flags;
          return this;
      }
      //查询系统的下载UI是否可见,默认false
      public Query setOnlyIncludeVisibleInDownloadsUi(boolean value) {
          mOnlyIncludeVisibleInDownloadsUi = value;
          return this;
      }
      
      
      /*改变查询结果的排序
      String column只支持COLUMN_LAST_MODIFIED_TIMESTAMP或者COLUMN_TOTAL_SIZE_BYTES
      int direction只支持ORDER_ASCENDING,ORDER_DESCENDING
      */
      public Query orderBy(String column, int direction) {
          if (direction != ORDER_ASCENDING && direction != ORDER_DESCENDING) {
              throw new IllegalArgumentException("Invalid direction: " + direction);
          }
      
          if (column.equals(COLUMN_LAST_MODIFIED_TIMESTAMP)) {
              mOrderByColumn = Downloads.Impl.COLUMN_LAST_MODIFICATION;
          } else if (column.equals(COLUMN_TOTAL_SIZE_BYTES)) {
              mOrderByColumn = Downloads.Impl.COLUMN_TOTAL_BYTES;
          } else {
              throw new IllegalArgumentException("Cannot order by " + column);
          }
          mOrderDirection = direction;
          return this;
      }
      
      //通过 ContentResolver.query(),返回cursor
      
      Cursor runQuery(ContentResolver resolver, String[] projection, Uri baseUri) {
          Uri uri = baseUri;
          List<String> selectionParts = new ArrayList<String>();
          String[] selectionArgs = null;
      
          if (mIds != null) {
              selectionParts.add(getWhereClauseForIds(mIds));
              selectionArgs = getWhereArgsForIds(mIds);
          }
      
          if (mStatusFlags != null) {
              List<String> parts = new ArrayList<String>();
              if ((mStatusFlags & STATUS_PENDING) != 0) {
                  parts.add(statusClause("=", Downloads.Impl.STATUS_PENDING));
              }
              if ((mStatusFlags & STATUS_RUNNING) != 0) {
                  parts.add(statusClause("=", Downloads.Impl.STATUS_RUNNING));
              }
              if ((mStatusFlags & STATUS_PAUSED) != 0) {
                  parts.add(statusClause("=", Downloads.Impl.STATUS_PAUSED_BY_APP));
                  parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_TO_RETRY));
                  parts.add(statusClause("=", Downloads.Impl.STATUS_WAITING_FOR_NETWORK));
                  parts.add(statusClause("=", Downloads.Impl.STATUS_QUEUED_FOR_WIFI));
              }
              if ((mStatusFlags & STATUS_SUCCESSFUL) != 0) {
                  parts.add(statusClause("=", Downloads.Impl.STATUS_SUCCESS));
              }
              if ((mStatusFlags & STATUS_FAILED) != 0) {
                  parts.add("(" + statusClause(">=", 400)
                            + " AND " + statusClause("<", 600) + ")");
              }
              selectionParts.add(joinStrings(" OR ", parts));
          }
      
          if (mOnlyIncludeVisibleInDownloadsUi) {
              selectionParts.add(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI + " != '0'");
          }
      
          // only return rows which are not marked 'deleted = 1'
          selectionParts.add(Downloads.Impl.COLUMN_DELETED + " != '1'");
      
          String selection = joinStrings(" AND ", selectionParts);
          String orderDirection = (mOrderDirection == ORDER_ASCENDING ? "ASC" : "DESC");
          String orderBy = mOrderByColumn + " " + orderDirection;
      
          return resolver.query(uri, projection, selection, selectionArgs, orderBy);
      }
      
      private String joinStrings(String joiner, Iterable<String> parts) {
          StringBuilder builder = new StringBuilder();
          boolean first = true;
          for (String part : parts) {
              if (!first) {
                  builder.append(joiner);
              }
              builder.append(part);
              first = false;
          }
          return builder.toString();
      }
      
      private String statusClause(String operator, int value) {
          return Downloads.Impl.COLUMN_STATUS + operator + "'" + value + "'";
       }
      }
    3. DownloadManager类的源码:

      • enqueue()对应源码:插入一条Requst信息,观察者模式下自动开始下载

        private ContentResolver mResolver;
        public long enqueue(Request request) {
             ContentValues values = request.toContentValues(mPackageName);
             Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
             long id = Long.parseLong(downloadUri.getLastPathSegment());
             return id;
        }
        
      • remove(): 更新id对应requst中删除标记

        public int remove(long... ids) {
           return markRowDeleted(ids);
        }
        public int markRowDeleted(long... ids) {
            if (ids == null || ids.length == 0) {
              // called with nothing to remove!
              throw new IllegalArgumentException("input param 'ids' can't be null");
             }
            ContentValues values = new ContentValues();
            values.put(Downloads.Impl.COLUMN_DELETED, 1);
             // if only one id is passed in, then include it in the uri itself.
            // this will eliminate a full database scan in the download service.
            if (ids.length == 1) {
               return mResolver.update(ContentUris.withAppendedId(mBaseUri, ids[0]),  
               values,null, null);
            } 
           return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
            getWhereArgsForIds(ids));
        }  
      • query():查询到一些关于下载的信息

        public Cursor query(Query query) {
           Cursor underlyingCursor = query.runQuery(mResolver,  
                  UNDERLYING_COLUMNS, mBaseUri);
           if (underlyingCursor == null) {
                 return null;
           }
          return new CursorTranslator(underlyingCursor, mBaseUri);
        } 
        //CursorTranslator这个类封装DownloadProvide返回的cursor,通过一些列信息,从而计算出需返回的数据 
      • addCompletedDownload():和enqueue()方法类似,唯一不的是这里有一个默认的Request
private static final String NON_DOWNLOADMANAGER_DOWNLOAD =
            "non-dwnldmngr-download-dont-retry2download";

      public long addCompletedDownload(String title, String description,
            boolean isMediaScannerScannable, String mimeType, String path, long length,
            boolean showNotification) {
        return addCompletedDownload(title, description, isMediaScannerScannable, mimeType, path,
                length, showNotification, false);
      }

    public long addCompletedDownload(String title, String description,
            boolean isMediaScannerScannable, String mimeType, String path, long length,
            boolean showNotification, boolean allowWrite) {
     //检查参数是否为空
        validateArgumentIsNonEmpty("title", title);
        validateArgumentIsNonEmpty("description", description);
        validateArgumentIsNonEmpty("path", path);
        validateArgumentIsNonEmpty("mimeType", mimeType);
        if (length < 0) {
            throw new IllegalArgumentException(" invalid value for param: totalBytes");
        }

        //在downloads.db中,给一个默认的路径,返回下载的id
        Request request = new Request(NON_DOWNLOADMANAGER_DOWNLOAD)
                .setTitle(title)
                .setDescription(description)
                .setMimeType(mimeType);
        ContentValues values = request.toContentValues(null);
        values.put(Downloads.Impl.COLUMN_DESTINATION,
                Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD);
        values.put(Downloads.Impl._DATA, path);
        values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_SUCCESS);
        values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, length);
        values.put(Downloads.Impl.COLUMN_MEDIA_SCANNED,
                (isMediaScannerScannable) ? Request.SCANNABLE_VALUE_YES :
                        Request.SCANNABLE_VALUE_NO);
        values.put(Downloads.Impl.COLUMN_VISIBILITY, (showNotification) ?
                Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION : Request.VISIBILITY_HIDDEN);
        values.put(Downloads.Impl.COLUMN_ALLOW_WRITE, allowWrite ? 1 : 0);
        Uri downloadUri = mResolver.insert(Downloads.Impl.CONTENT_URI, values);
        if (downloadUri == null) {
            return -1;
        }
        return Long.parseLong(downloadUri.getLastPathSegment());
    }

通过查看DownloadManager的源码发现:添加下载的任务,移除下载的任务,都是对数据库中数据的增,改操作。然后结合观察者模式实现自动调配,下载任务。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Internet Download Manager(IDM)是一款功能强大的下载管理软件,它的64位版本能够更好地兼容和利用64位操作系统的资。 IDM 64位版本的主要优点是能够完全充分利用64位操作系统的资,从而提供更高的下载速度和更稳定的性能。与32位版本相比,它能更好地处理大容量文件的下载,同时还能更好地支持多线程下载,提供更快速和高效的下载体验。 通过IDM 64位版本,用户可以同时下载多个文件,并且每个文件的下载速度都能达到最大可能值。这个特点对于需下载大型文件或需要进行大量下载任务的用户非常有吸引力。 除了具备更高的下载速度和更强的稳定性外,IDM 64位版本还提供了更丰富的功能和更灵活的设置选项。用户可以自定义下载目录和下载优先级,还可以设定下载任务的时间计划,实现自动下载和管理。此外,它还支持断点续传功能,即使在下载过程中意外中断或网络波动,用户也能够轻松地恢复下载进度。 总而言之,IDM 64位版本是一款强大且高效的下载管理软件,它利用64位操作系统的资,提供了更高的下载速度和更稳定的性能。无论你是需要频繁进行大容量文件的下载或是只是想要提高下载速度和方便性,IDM 64位版本都能满足你的需求。 ### 回答2: Internet Download Manager (IDM)是一款功能强大的下载管理器,它的64位版本提供了更好的性能和兼容性。这个版本适用于64位操作系统的用户,包括Windows 7、8、10等系统。 IDM 64位版本具有以下优点: 1.更好的性能:64位版本能够更充分地利用计算机的内存和处理器资,从而提供更快的下载速度和更高的稳定性。这对于下载大文件或进行多任务下载的用户来说非常重要。 2.兼容性更强:64位版本可以与64位操作系统和软件完美兼容,确保了更好的稳定性和兼容性。这使得IDM能够顺利运行,并与其他应用程序无缝集成。 3.更大的文件支持:64位版本可以处理更大的文件,支持超过4GB的文件下载。这对于需要下载大型影视文件、游戏、软件或其他大文件的用户非常有用。 4.更多的扩展支持:64位版本还提供了更多的浏览器扩展支持。用户可以将IDM与不同浏览器(如Chrome、Firefox、Edge等)集成,以方便地捕获和下载网页上的媒体内容和文件。 总之,IDM 64位版本是一个功能强大的下载管理器,具有更好的性能、兼容性和文件处理能力。如果您是一位64位操作系统的用户,我强烈推荐您使用这个版本来提高下载效率和体验。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值