DownloadProvider 源码详细分析
生活随笔
收集整理的這篇文章主要介紹了
DownloadProvider 源码详细分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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沒有啟動將會執行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> |
從這個時序圖可以看出,這里涉及的源碼比較多,在這沒有寫,看的時候一定要對照的源碼來看。其實在下載的時候會發生很多的異常,如網絡異常,內存卡容量不足等,所以捕獲異常很重要的,捕獲后進行相關的處理,這也是體現出考慮全面的地方。?
總結
以上是生活随笔為你收集整理的DownloadProvider 源码详细分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谁执我之手
- 下一篇: #研发解决方案介绍#基于StatsD+G