精华内容
下载资源
问答
  • DownloadProvider

    2011-06-15 20:17:06
    DownloadProvider
    DownloadProvider
    展开全文
  • Android DownloadProvider 源码分析: Download的源码编译分为两个部分,一个是DownloadProvider.apk, 一个是DownloadProviderUi.apk. 这两个apk的源码分别位于 packages/providers/DownloadProvider/ui/src ...
  • 系统DownloadProvider

    2016-11-08 10:08:13
    因为解一个bug,所以大体的看了下Android4.3 的DownloadProvider模块,现在通过在写博客的过程中进一步的熟悉它,首先其源码位置于package/provider/DownloadProvider;界面部分代码在packages/providers/...

    因为解一个bug,所以大体的看了下Android4.3 的DownloadProvider模块,现在通过在写博客的过程中进一步的熟悉它,首先其源码位置于package/provider/DownloadProvider;

    界面部分代码在packages/providers/DownloadProvider/ui/src下;
    逻辑部分代码位于packages/providers/DownloadProvider/src下;

    首先介绍几个关键的类,来有个大体的认识:

    1、DownloadProvider:看名字就知道它是数据库操作的封装,继承自ContentProvider;
    2、DownloadManager:大部分逻辑是进一步封装数据操作,供外部调用;
    3、DownloadService:封装文件download,delete等操作,并且操纵下载的norification;继承自Service;
    4、DownloadNotifier:状态栏Notification逻辑;
    5、DownloadReceiver:配合DownloadNotifier进行文件的操作及其Notification;
    6、DownloadList:Download app主界面,文件界面交互;

    接下来还需要看一下Download的DataBase结构;它包括两张表:downloads和request_headers,来看看创建代码:

    private void createDownloadsTable(SQLiteDatabase db) {
    try {
    db.execSQL(“DROP TABLE IF EXISTS ” + DB_TABLE);
    db.execSQL(“CREATE TABLE ” + DB_TABLE + “(” +
    Downloads.Impl._ID + ” INTEGER PRIMARY KEY AUTOINCREMENT,” +
    Downloads.Impl.COLUMN_URI + ” TEXT, ” +
    Constants.RETRY_AFTER_X_REDIRECT_COUNT + ” INTEGER, ” +
    Downloads.Impl.COLUMN_APP_DATA + ” TEXT, ” +
    Downloads.Impl.COLUMN_NO_INTEGRITY + ” BOOLEAN, ” +
    Downloads.Impl.COLUMN_FILE_NAME_HINT + ” TEXT, ” +
    Constants.OTA_UPDATE + ” BOOLEAN, ” +
    Downloads.Impl._DATA + ” TEXT, ” +
    Downloads.Impl.COLUMN_MIME_TYPE + ” TEXT, ” +
    Downloads.Impl.COLUMN_DESTINATION + ” INTEGER, ” +
    Constants.NO_SYSTEM_FILES + ” BOOLEAN, ” +
    Downloads.Impl.COLUMN_VISIBILITY + ” INTEGER, ” +
    Downloads.Impl.COLUMN_CONTROL + ” INTEGER, ” +
    Downloads.Impl.COLUMN_STATUS + ” INTEGER, ” +
    Downloads.Impl.COLUMN_FAILED_CONNECTIONS + ” INTEGER, ” +
    Downloads.Impl.COLUMN_LAST_MODIFICATION + ” BIGINT, ” +
    Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE + ” TEXT, ” +
    Downloads.Impl.COLUMN_NOTIFICATION_CLASS + ” TEXT, ” +
    Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS + ” TEXT, ” +
    Downloads.Impl.COLUMN_COOKIE_DATA + ” TEXT, ” +
    Downloads.Impl.COLUMN_USER_AGENT + ” TEXT, ” +
    Downloads.Impl.COLUMN_REFERER + ” TEXT, ” +
    Downloads.Impl.COLUMN_TOTAL_BYTES + ” INTEGER, ” +
    Downloads.Impl.COLUMN_CURRENT_BYTES + ” INTEGER, ” +
    Constants.ETAG + ” TEXT, ” +
    Constants.UID + ” INTEGER, ” +
    Downloads.Impl.COLUMN_OTHER_UID + ” INTEGER, ” +
    Downloads.Impl.COLUMN_TITLE + ” TEXT, ” +
    Downloads.Impl.COLUMN_DESCRIPTION + ” TEXT, ” +
    Constants.MEDIA_SCANNED + ” BOOLEAN);”);
    } catch (SQLException ex) {
    Log.e(Constants.TAG, “couldn’t create table in downloads database”);
    throw ex;
    }
    }

    private void createHeadersTable(SQLiteDatabase db) {
    db.execSQL(“DROP TABLE IF EXISTS ” + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE);
    db.execSQL(“CREATE TABLE ” + Downloads.Impl.RequestHeaders.HEADERS_DB_TABLE + “(” +
    “id INTEGER PRIMARY KEY AUTOINCREMENT,” +
    Downloads.Impl.RequestHeaders.COLUMN_DOWNLOAD_ID + ” INTEGER NOT NULL,” +
    Downloads.Impl.RequestHeaders.COLUMN_HEADER + ” TEXT NOT NULL,” +
    Downloads.Impl.RequestHeaders.COLUMN_VALUE + ” TEXT NOT NULL” +
    “);”);
    }
    解析需要按照一个主要的流程来讲解,我就以Browser中下载文件来作为讲解的入口吧;

    首先,当我在网页中点击下载文件按钮后,开始下载文件,这里Browser中调用的代码是:

    …..
    //初始化一个Uri对象
    Uri uri = Uri.parse(addressString);
    final DownloadManager.Request request;
    try {
    request = new DownloadManager.Request(uri);
    } catch (IllegalArgumentException e) {
    Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show();
    return;
    }
    request.setMimeType(mimetype);
    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
    request.allowScanningByMediaScanner();
    request.setDescription(webAddress.getHost());
    String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing);
    request.addRequestHeader(“cookie”, cookies);
    request.addRequestHeader(“User-Agent”, userAgent);
    request.addRequestHeader(“Referer”, referer);
    request.setNotificationVisibility(
    DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    …..
    final DownloadManager manager
    = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
    new Thread(“Browser download”) {
    public void run() {
    manager.enqueue(request);
    }
    }.start();
    …..
    获得DownloadManager的实例,组建一个DownloadManager.Request参数,在线程中调用其enqueue函数进行下载请求;看看这个qnqueue函数做了什么:

    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;
    }
    enqueue函数主要是将Rquest实例分解组成一个ContentValues实例,并且添加到数据库中,函数返回插入的这条数据返回的ID;

    ContentResolver.insert函数会调用到DownloadProvider实现的ContentProvider的insert函数中去;

    ……
    //将相关的请求参数,配置等插入到downloads数据库;
    long rowID = db.insert(DB_TABLE, null, filteredValues);
    ……
    //将相关的请求参数,配置等插入到request_headers数据库中;
    insertRequestHeaders(db, rowID, values);
    ……
    if (values.getAsInteger(Downloads.Impl.COLUMN_DESTINATION) ==
    Downloads.Impl.DESTINATION_NON_DOWNLOADMANAGER_DOWNLOAD) {
    // When notification is requested, kick off service to process all
    // relevant downloads.
    //启动DownloadService进行下载及其它工作
    if (Downloads.Impl.isNotificationToBeDisplayed(vis)) {
    context.startService(new Intent(context, DownloadService.class));
    }
    } else {
    context.startService(new Intent(context, DownloadService.class));
    }
    notifyContentChanged(uri, match);
    return ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, rowID);
    接下来就是DownloadService,应该是大头了,主要的下载任务就是通过它来完成的;startService启动DownloadService,首先当然是OnCreate函数了:

    @Override
    public void onCreate() {
    super.onCreate();
    ……
    //mUpdateThread 以及mUpdateHandler
    mUpdateThread = new HandlerThread(TAG + “-UpdateThread”);
    mUpdateThread.start();
    mUpdateHandler = new Handler(mUpdateThread.getLooper(), mUpdateCallback);

        mScanner = new DownloadScanner(this);
    

    //DownloadNotifier对象
    mNotifier = new DownloadNotifier(this);
    mNotifier.cancelAll();

        mObserver = new DownloadManagerContentObserver();
    

    //注册监听Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI的Observer
    getContentResolver().registerContentObserver(Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI,
    true, mObserver);
    }
    创建的一个HandlerThread对象mUpdateThread并且start;用Handler、Message来进行后续的逻辑处理;

    再来看看OnStartCommand函数:

    private Handler.Callback mUpdateCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    final int startId = msg.arg1;
    final boolean isActive;
    synchronized (mDownloads) {
    isActive = updateLocked();
    }
    ……
    if (isActive) {
    //如果Active,则会在Delayed 5×60000ms后发送MSG_FINAL_UPDATE Message,主要是为了“any finished operations that didn’t trigger an update pass.”
    enqueueFinalUpdate();
    } else {
    //如果没有Active的任务正在进行,就会停止Service以及其它
    if (stopSelfResult(startId)) {
    if (DEBUG_LIFECYCLE) Log.v(TAG, “Nothing left; stopped”);
    getContentResolver().unregisterContentObserver(mObserver);
    mScanner.shutdown();
    mUpdateThread.quit();
    }
    }
    return true;
    }
    };
    重点是updateLocked()函数,我们来看看;

    private boolean updateLocked() {
        final long now = mSystemFacade.currentTimeMillis();
    
        boolean isActive = false;
        long nextActionMillis = Long.MAX_VALUE;
    

    //mDownloads初始化是一个空的Map

    展开全文
  • DownloadProvider 简介

    2015-08-05 10:45:14
    DownloadProvider 简介 DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。源码下载地址 DownloadProvider ...

    DownloadProvider 简介

    DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。源码下载地址

    DownloadProvider 详细分析

    DownloadProvider开始下载的是由DownloadManager 的 enqueue方法启动的,启动一个新的下载任务的时序图
    \

    开始新的下载时候会调用DownloadManager的enqueue方法,然后再执行DownloadProvider的insert方法,将下载信息写入数据库,包括下载链接地址等,然后再调用DownloadService的onCreate或者onStartCommand方法。 DownloadProvider类是非常重要的类,所有操作都跟此类有关,因为要保存下载状态。 在分析DownloadProvider的insert方法前,先看看insert方法的源码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    @Override
    public Uri insert(final Uri uri, final ContentValues values) {
        checkInsertPermissions(values);
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
     
        // note we disallow inserting into ALL_DOWNLOADS
        int match = sURIMatcher.match(uri);
        if (match != MY_DOWNLOADS) {
            Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: "
                    + uri);
            throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
        }
     
        ContentValues filteredValues = new ContentValues();
     
        ......
     
        Integer dest = values.getAsInteger(Downloads.COLUMN_DESTINATION);
        if (dest != null) {
         
            ......
             
        }
        Integer vis = values.getAsInteger(Downloads.COLUMN_VISIBILITY);
        if (vis == null) {
            if (dest == Downloads.DESTINATION_EXTERNAL) {
                filteredValues.put(Downloads.COLUMN_VISIBILITY,
                        Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            } else {
                filteredValues.put(Downloads.COLUMN_VISIBILITY,
                        Downloads.VISIBILITY_HIDDEN);
            }
        } else {
            filteredValues.put(Downloads.COLUMN_VISIBILITY, vis);
        }
        ......
     
        String pckg = values.getAsString(Downloads.COLUMN_NOTIFICATION_PACKAGE);
        String clazz = values.getAsString(Downloads.COLUMN_NOTIFICATION_CLASS);
        if (pckg != null && (clazz != null || isPublicApi)) {
            ......
        }
        ......
     
        //启动下载服务
        Context context = getContext();
        context.startService(new Intent(context, DownloadService.class));
     
        //插入数据库
        long rowID = db.insert(DB_TABLE, null, filteredValues);
        if (rowID == -1) {
            Log.d(Constants.TAG, "couldn't insert into downloads database");
            return null;
        }
     
        insertRequestHeaders(db, rowID, values);
        //启动下载服务
        context.startService(new Intent(context, DownloadService.class));
        notifyContentChanged(uri, match);
        return ContentUris.withAppendedId(Downloads.CONTENT_URI, rowID);
    }
    每次开始一个新的下载任务,都会插入数据库,然后启动启动下载服务类DownloadService,所以真正处理下载的是后台服务DownloadService,DownloadService中有个下载线程类DownloadThread,DownloadService时序图
    \

    如果DownloadService没有启动将会执行onCreate()------>onStartCommand()方法,否则执行onStartCommand()方法。然后执行updateFromProvider()方法启动UpdateThread线程,准备启动DownloadThread线程。 分析UpdateThread的run方法前先看看run方法的源码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
     
        //如果数据里的存储的达到了1000以上时候,将会删除status>200即失败的记录
        trimDatabase();
        removeSpuriousFiles();
     
        boolean keepService = false;
        // for each update from the database, remember which download is
        // supposed to get restarted soonest in the future
        long wakeUp = Long.MAX_VALUE;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
            //会一直在此循环,直到启动完所有下载任务
        for (;;) {
            synchronized (DownloadService.this) {
                if (mUpdateThread != this) {
                    throw new IllegalStateException(
                            "multiple UpdateThreads in DownloadService");
                }
                if (!mPendingUpdate) {
                    mUpdateThread = null;
                    if (!keepService) {
                        stopSelf();
                    }
                    if (wakeUp != Long.MAX_VALUE) {
                        scheduleAlarm(wakeUp);
                    }
                    return;
                }
                mPendingUpdate = false;
            }
     
            long now = mSystemFacade.currentTimeMillis();
            keepService = false;
            wakeUp = Long.MAX_VALUE;
            Set<long> idsNoLongerInDatabase = new HashSet<long>(
                    mDownloads.keySet());
     
            Cursor cursor = getContentResolver().query(
                    Downloads.ALL_DOWNLOADS_CONTENT_URI, null, null, null,
                    null);
            if (cursor == null) {
                continue;
            }
            try {
                DownloadInfo.Reader reader = new DownloadInfo.Reader(
                        getContentResolver(), cursor);
                int idColumn = cursor.getColumnIndexOrThrow(Downloads._ID);
     
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
                        .moveToNext()) {
                    long id = cursor.getLong(idColumn);
                    idsNoLongerInDatabase.remove(id);
                    DownloadInfo info = mDownloads.get(id);
                    if (info != null) {
                        updateDownload(reader, info, now);
                    } else {
                        info = insertDownload(reader, now);
                    }
                    if (info.hasCompletionNotification()) {
                        keepService = true;
                    }
                    long next = info.nextAction(now);
                    if (next == 0) {
                        keepService = true;
                    } else if (next > 0 && next < wakeUp) {
                        wakeUp = next;
                    }
                }
            } finally {
                cursor.close();
            }
     
            for (Long id : idsNoLongerInDatabase) {
                deleteDownload(id);
            }
     
            // is there a need to start the DownloadService? yes, if there
            // are rows to be deleted.
     
            for (DownloadInfo info : mDownloads.values()) {
                if (info.mDeleted) {
                    keepService = true;
                    break;
                }
            }
     
            mNotifier.updateNotification(mDownloads.values());
     
            // look for all rows with deleted flag set and delete the rows
            // from the database
            // permanently
            for (DownloadInfo info : mDownloads.values()) {
                if (info.mDeleted) {
                    Helpers.deleteFile(getContentResolver(), info.mId,
                            info.mFileName, info.mMimeType);
                }
            }
        }
    }</long></long>
    UpdateThread线程负责从数据库中获取下载任务,该线程不会每次都新建新的对象,只有UpdateThread为空时候才会新建,在此线程的run()方法中有两个for循环,外循环是从数据获取下载任务,确保插入数据库的任务都能被启动,直到启动完所有的下载任务才会退出。内循环是遍历从数据库获取的没完成或者刚开始的下载任务,启动下载。 DownloadThrea线程是真正负责下载的线程,每次启动一个任务都会创建一个新的下载线程对象(对手机来说会耗很大的CPU,所有要加上同步锁或者线程池来控制同时下载的数量),看看DownloadThread run方法的时序图:
    从这个时序图可以看出,这里涉及的源码比较多,在这没有写,看的时候一定要对照的源码来看。其实在下载的时候会发生很多的异常,如网络异常,内存卡容量不足等,所以捕获异常很重要的,捕获后进行相关的处理,这也是体现出考虑全面的地方。
    展开全文
  • DownloadProvider 简介 DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。源码下载地址 DownloadProvider ...

    DownloadProvider 简介

    DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。源码下载地址

    DownloadProvider 详细分析

    DownloadProvider开始下载的是由DownloadManager 的 enqueue方法启动的,启动一个新的下载任务的时序图
    \

    开始新的下载时候会调用DownloadManager的enqueue方法,然后再执行DownloadProvider的insert方法,将下载信 息写入数据库,包括下载链接地址等,然后再调用DownloadService的onCreate或者onStartCommand方法。 DownloadProvider类是非常重要的类,所有操作都跟此类有关,因为要保存下载状态。 在分析DownloadProvider的insert方法前,先看看insert方法的源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    @Override
    public Uri insert(final Uri uri, final ContentValues values) {
        checkInsertPermissions(values);
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
     
        // note we disallow inserting into ALL_DOWNLOADS
        int match = sURIMatcher.match(uri);
        if (match != MY_DOWNLOADS) {
            Log.d(Constants.TAG, "calling insert on an unknown/invalid URI: "
                    + uri);
            throw new IllegalArgumentException("Unknown/Invalid URI " + uri);
        }
     
        ContentValues filteredValues = new ContentValues();
     
        ......
     
        Integer dest = values.getAsInteger(Downloads.COLUMN_DESTINATION);
        if (dest != null) {
         
            ......
             
        }
        Integer vis = values.getAsInteger(Downloads.COLUMN_VISIBILITY);
        if (vis == null) {
            if (dest == Downloads.DESTINATION_EXTERNAL) {
                filteredValues.put(Downloads.COLUMN_VISIBILITY,
                        Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            } else {
                filteredValues.put(Downloads.COLUMN_VISIBILITY,
                        Downloads.VISIBILITY_HIDDEN);
            }
        } else {
            filteredValues.put(Downloads.COLUMN_VISIBILITY, vis);
        }
        ......
     
        String pckg = values.getAsString(Downloads.COLUMN_NOTIFICATION_PACKAGE);
        String clazz = values.getAsString(Downloads.COLUMN_NOTIFICATION_CLASS);
        if (pckg != null && (clazz != null || isPublicApi)) {
            ......
        }
        ......
     
        //启动下载服务
        Context context = getContext();
        context.startService(new Intent(context, DownloadService.class));
     
        //插入数据库
        long rowID = db.insert(DB_TABLE, null, filteredValues);
        if (rowID == -1) {
            Log.d(Constants.TAG, "couldn't insert into downloads database");
            return null;
        }
     
        insertRequestHeaders(db, rowID, values);
        //启动下载服务
        context.startService(new Intent(context, DownloadService.class));
        notifyContentChanged(uri, match);
        return ContentUris.withAppendedId(Downloads.CONTENT_URI, rowID);
    }

    每次开始一个新的下载任务,都会插入数据库,然后启动启动下载服务类DownloadService,所以真正处理下载的是后台服务 DownloadService,DownloadService中有个下载线程类DownloadThread,DownloadService时序图
    \

    如果DownloadService没有启动将会执行onCreate()------>onStartCommand()方法,否则执行 onStartCommand()方法。然后执行updateFromProvider()方法启动UpdateThread线程,准备启动 DownloadThread线程。 分析UpdateThread的run方法前先看看run方法的源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
     
        //如果数据里的存储的达到了1000以上时候,将会删除status>200即失败的记录
        trimDatabase();
        removeSpuriousFiles();
     
        boolean keepService = false;
        // for each update from the database, remember which download is
        // supposed to get restarted soonest in the future
        long wakeUp = Long.MAX_VALUE;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
            //会一直在此循环,直到启动完所有下载任务
        for (;;) {
            synchronized (DownloadService.this) {
                if (mUpdateThread != this) {
                    throw new IllegalStateException(
                            "multiple UpdateThreads in DownloadService");
                }
                if (!mPendingUpdate) {
                    mUpdateThread = null;
                    if (!keepService) {
                        stopSelf();
                    }
                    if (wakeUp != Long.MAX_VALUE) {
                        scheduleAlarm(wakeUp);
                    }
                    return;
                }
                mPendingUpdate = false;
            }
     
            long now = mSystemFacade.currentTimeMillis();
            keepService = false;
            wakeUp = Long.MAX_VALUE;
            Set<long> idsNoLongerInDatabase = new HashSet<long>(
                    mDownloads.keySet());
     
            Cursor cursor = getContentResolver().query(
                    Downloads.ALL_DOWNLOADS_CONTENT_URI, null, null, null,
                    null);
            if (cursor == null) {
                continue;
            }
            try {
                DownloadInfo.Reader reader = new DownloadInfo.Reader(
                        getContentResolver(), cursor);
                int idColumn = cursor.getColumnIndexOrThrow(Downloads._ID);
     
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
                        .moveToNext()) {
                    long id = cursor.getLong(idColumn);
                    idsNoLongerInDatabase.remove(id);
                    DownloadInfo info = mDownloads.get(id);
                    if (info != null) {
                        updateDownload(reader, info, now);
                    } else {
                        info = insertDownload(reader, now);
                    }
                    if (info.hasCompletionNotification()) {
                        keepService = true;
                    }
                    long next = info.nextAction(now);
                    if (next == 0) {
                        keepService = true;
                    } else if (next > 0 && next < wakeUp) {
                        wakeUp = next;
                    }
                }
            } finally {
                cursor.close();
            }
     
            for (Long id : idsNoLongerInDatabase) {
                deleteDownload(id);
            }
     
            // is there a need to start the DownloadService? yes, if there
            // are rows to be deleted.
     
            for (DownloadInfo info : mDownloads.values()) {
                if (info.mDeleted) {
                    keepService = true;
                    break;
                }
            }
     
            mNotifier.updateNotification(mDownloads.values());
     
            // look for all rows with deleted flag set and delete the rows
            // from the database
            // permanently
            for (DownloadInfo info : mDownloads.values()) {
                if (info.mDeleted) {
                    Helpers.deleteFile(getContentResolver(), info.mId,
                            info.mFileName, info.mMimeType);
                }
            }
        }
    }</long></long>

    UpdateThread线程负责从数据库中获取下载任务,该线程不会每次都新建新的对象,只有UpdateThread为空时候才会新建,在此线程的 run()方法中有两个for循环,外循环是从数据获取下载任务,确保插入数据库的任务都能被启动,直到启动完所有的下载任务才会退出。内循环是遍历从数 据库获取的没完成或者刚开始的下载任务,启动下载。 DownloadThrea线程是真正负责下载的线程,每次启动一个任务都会创建一个新的下载线程对象(对手机来说会耗很大的CPU,所有要加上同步锁或 者线程池来控制同时下载的数量),看看DownloadThread run方法的时序图:
    从这个时序图可以看出,这里涉及的源码比较多,在这没有写,看的时候一定要对照的源码来看。其实在下载的时候会发生很多的异常,如网络异常,内存卡容量不足等,所以捕获异常很重要的,捕获后进行相关的处理,这也是体现出考虑全面的地方。

    转载于:https://www.cnblogs.com/kings-boke/p/4504253.html

    展开全文
  • yxl/DownloadProvider

    2019-10-06 00:29:06
    yxl/DownloadProvider yxl/DownloadProviderThis project ports the DownloadProvider of Android 2.3.7. It supports Android 2.2 and above....
  • DownloadProvider介绍

    千次阅读 2015-04-05 23:57:30
    DownloadProvider提供了一个保存数据的格式,如content://downloads/my_downloads/1,或content://downloads/all_downloads/2。第三方应用可以使用DownloadManager的enqueue(Request)方法来请求下载,并可以使用...
  • android利用系统DownloadProvider实现下载,多文件多线程后台下载,有需要下载功能的可以直接导入到程序中
  • DownloadProvider 详细分析

    千次阅读 2014-11-20 15:09:49
    DownloadProvider 简介 DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。 DownloadProvider开始下载的是由...
  • 修改过的DownloadProvider-master,方便大家使用
  • android 7.0 Downloadprovider 下载流程

    千次阅读 2017-03-22 13:58:50
    1.Downloadprovider 源码路径 Download的源码编译分为两个部分,一个是DownloadProvider.apk, 一个是DownloadProviderUi.apk.这两个apk的源码分别位于  packages/providers/DownloadProvider/ui/src  packages/...
  • DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载”,“删除下载”接口。源码下载地址 DownloadProvider 详细分析 DownloadP
  • Android DownloadProvider 源码分析

    千次阅读 2014-03-28 11:52:32
    Download的源码编译分为两个部分,一个是DownloadProvider.apk, 一个是DownloadProviderUi.apk.
  • 找了很多都说github上https://github.com/yxl/DownloadProvider/ 这个比较好,所以就下载下来啦,不知道怎么回事我前段时间还可以下载,现在就出错啦,后台还报错啦,而且之前好的时候我把这个放到我项目中就直接不...
  • 最近在安卓4.4上遇到一个断开wifi后重新连接wifi, downloadProvider继续下载文件失败的问题。于是开始了解下载管理模块的断点续载功能: 1、首先,分析android log, 当将网络断开之后,下载会中止,出现如下...
  • Android 下载模块分析(DownloadManager和DownloadProvider) Android下载模块主要有2个部分组成:DownloadManager和DownloadProvider;其中DownloadManager提供接口供调用,具体的实现是DownloadProvider,...
  • Android内部提供了一个DownloadProvider,是一个非常完整的下载工具,提供了很好的外部接口可以被其他应用程序调用,来完成下载工作。同时也提供和很好的下载、通知、存储等机制。 在Android的Browser等工具里面都...
  • 因为解一个bug,所以大体的看了下Android4.3 的DownloadProvider模块,现在通过在写博客的过程中进一步的熟悉它,首先其源码位置于package/provider/DownloadProvider; 界面部分代码在packages/providers/...
  • 使用DownloadProvider来完成下载任务

    千次阅读 2013-10-15 18:06:03
    这对于很多开发者来说,都不是什么大的问题,网上也可以搜索出很多的源码出来进行下载,也就是用httpClient,方法很多,我这里就不说了,这里我要说的是利用2.3本身已经打开的 DownloadProvider这个API来进行下载,...
  • 08-27 18:18:29.669: E/ContentValues(1837): at com.mozillaonline.providers.downloads.DownloadProvider.copyBoolean(DownloadProvider.java:1109) 08-27 18:18:29.669: E/ContentValues(1837): at ...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 150
精华内容 60
关键字:

downloadprovider