日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DownloadProvider 源码详细分析

發(fā)布時間:2025/4/16 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DownloadProvider 源码详细分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
DownloadProvider 簡介
DownloadProvider 是Android提供的DownloadManager的增強(qiáng)版,亮點是支持?jǐn)帱c下載,提供了“開始下載”,“暫停下載”,“重新下載”,“刪除下載”接口。源碼下載地址

DownloadProvider 詳細(xì)分析

DownloadProvider開始下載的是由DownloadManager 的 enqueue方法啟動的,啟動一個新的下載任務(wù)的時序圖?


開始新的下載時候會調(diào)用DownloadManager的enqueue方法,然后再執(zhí)行DownloadProvider的insert方法,將下載信息寫入數(shù)據(jù)庫,包括下載鏈接地址等,然后再調(diào)用DownloadService的onCreate或者onStartCommand方法。 DownloadProvider類是非常重要的類,所有操作都跟此類有關(guān),因為要保存下載狀態(tài)。 在分析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)) { ????????...... ????} ????...... ????//啟動下載服務(wù) ????Context context = getContext(); ????context.startService(new Intent(context, DownloadService.class)); ????//插入數(shù)據(jù)庫 ????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); ????//啟動下載服務(wù) ????context.startService(new Intent(context, DownloadService.class)); ????notifyContentChanged(uri, match); ????return ContentUris.withAppendedId(Downloads.CONTENT_URI, rowID); }
每次開始一個新的下載任務(wù),都會插入數(shù)據(jù)庫,然后啟動啟動下載服務(wù)類DownloadService,所以真正處理下載的是后臺服務(wù)DownloadService,DownloadService中有個下載線程類DownloadThread,DownloadService時序圖?


如果DownloadService沒有啟動將會執(zhí)行onCreate()------>onStartCommand()方法,否則執(zhí)行onStartCommand()方法。然后執(zhí)行updateFromProvider()方法啟動UpdateThread線程,準(zhǔn)備啟動DownloadThread線程。 分析UpdateThread的run方法前先看看run方法的源碼: ?
1 2 3 4 5 6 7 8 9 10 11 public void run() { ????Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); ????//如果數(shù)據(jù)里的存儲的達(dá)到了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 ????????//會一直在此循環(huán),直到啟動完所有下載任務(wù) ????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線程負(fù)責(zé)從數(shù)據(jù)庫中獲取下載任務(wù),該線程不會每次都新建新的對象,只有UpdateThread為空時候才會新建,在此線程的run()方法中有兩個for循環(huán),外循環(huán)是從數(shù)據(jù)獲取下載任務(wù),確保插入數(shù)據(jù)庫的任務(wù)都能被啟動,直到啟動完所有的下載任務(wù)才會退出。內(nèi)循環(huán)是遍歷從數(shù)據(jù)庫獲取的沒完成或者剛開始的下載任務(wù),啟動下載。 DownloadThrea線程是真正負(fù)責(zé)下載的線程,每次啟動一個任務(wù)都會創(chuàng)建一個新的下載線程對象(對手機(jī)來說會耗很大的CPU,所有要加上同步鎖或者線程池來控制同時下載的數(shù)量),看看DownloadThread run方法的時序圖:?
從這個時序圖可以看出,這里涉及的源碼比較多,在這沒有寫,看的時候一定要對照的源碼來看。其實在下載的時候會發(fā)生很多的異常,如網(wǎng)絡(luò)異常,內(nèi)存卡容量不足等,所以捕獲異常很重要的,捕獲后進(jìn)行相關(guān)的處理,這也是體現(xiàn)出考慮全面的地方。?


總結(jié)

以上是生活随笔為你收集整理的DownloadProvider 源码详细分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。