Android之 多线程下载、断点续传 实现

来源:互联网 发布:二维dct变换矩阵 编辑:程序博客网 时间:2024/05/16 03:28

这里使用的是github上的一个开源项目 DownloadProvider  下载地址:https://github.com/yxl/DownloadProvider,支持多线程下载和断点续传功能,自己在它上面作了一些修改以满足业务需求。

先看效果图吧:



通知栏下载进度 提示





工程目录结构如下:




清单文件

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.downloadtest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="8"  
  9.         android:targetSdkVersion="17" />  
  10.       
  11.     <!-- Allows access to the Download Manager -->  
  12.     <permission  
  13.         android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER"  
  14.         android:description="@string/permdesc_downloadManager"  
  15.         android:label="@string/permlab_downloadManager"  
  16.         android:protectionLevel="normal" />  
  17.   
  18.     <!-- Allows advanced access to the Download Manager -->  
  19.     <permission  
  20.         android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED"  
  21.         android:description="@string/permdesc_downloadManagerAdvanced"  
  22.         android:label="@string/permlab_downloadManagerAdvanced"  
  23.         android:protectionLevel="normal" />  
  24.   
  25.     <!-- Allows to send broadcasts on download completion -->  
  26.     <permission  
  27.         android:name="com.example.downloadtest.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"  
  28.         android:description="@string/permdesc_downloadCompletedIntent"  
  29.         android:label="@string/permlab_downloadCompletedIntent"  
  30.         android:protectionLevel="normal" />  
  31.   
  32.     <uses-permission android:name="android.permission.INTERNET" />  
  33.     <uses-permission android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER" />  
  34.     <uses-permission android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />  
  35.     <uses-permission android:name="com.example.downloadtest.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" />  
  36.     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
  37.     <uses-permission android:name="android.permission.WAKE_LOCK" />  
  38.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  39.       
  40.   
  41.     <application  
  42.         android:allowBackup="true"  
  43.         android:icon="@drawable/ic_launcher"  
  44.         android:label="@string/app_name"  
  45.         android:theme="@style/AppTheme" android:name=".app.MyApplication">  
  46.         <activity  
  47.             android:name="com.example.downloadtest.MainActivity"  
  48.             android:label="@string/app_name" >  
  49.             <intent-filter>  
  50.                 <action android:name="android.intent.action.MAIN" />  
  51.   
  52.                 <category android:name="android.intent.category.LAUNCHER" />  
  53.             </intent-filter>  
  54.         </activity>  
  55.           
  56.         <provider  
  57.             android:name="com.example.downloadtest.providers.downloads.DownloadProvider"  
  58.             android:authorities="com.example.downloadtest.downloads" android:exported="false"/>  
  59.   
  60.         <service android:name="com.example.downloadtest.providers.downloads.DownloadService" />  
  61.   
  62.         <receiver  
  63.             android:name="com.example.downloadtest.providers.downloads.DownloadReceiver"  
  64.             android:exported="false" >  
  65.             <intent-filter>  
  66.                 <action android:name="android.intent.action.BOOT_COMPLETED" />  
  67.                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />  
  68.             </intent-filter>  
  69.         </receiver>  
  70.           
  71.     </application>  
  72.   
  73. </manifest>  



界面布局文件 activity_main.xml

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context=".MainActivity" >  
  6.   
  7.     <ListView  
  8.         android:id="@+id/mListView"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="match_parent"   
  11.         android:cacheColorHint="@android:color/transparent"/>  
  12.   
  13. </RelativeLayout>  


MainActivity.java

[java] view plaincopy
  1. package com.example.downloadtest;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.content.Context;  
  8. import android.database.ContentObserver;  
  9. import android.database.Cursor;  
  10. import android.net.Uri;  
  11. import android.os.Bundle;  
  12. import android.os.Environment;  
  13. import android.os.Handler;  
  14. import android.util.Log;  
  15. import android.view.LayoutInflater;  
  16. import android.view.View;  
  17. import android.view.View.OnClickListener;  
  18. import android.view.ViewGroup;  
  19. import android.widget.BaseAdapter;  
  20. import android.widget.Button;  
  21. import android.widget.ListView;  
  22. import android.widget.ProgressBar;  
  23. import android.widget.TextView;  
  24. import android.widget.Toast;  
  25.   
  26. import com.example.downloadtest.app.MyApplication;  
  27. import com.example.downloadtest.entity.AppInfo;  
  28. import com.example.downloadtest.entity.DownloadItem;  
  29. import com.example.downloadtest.providers.DownloadManager;  
  30. import com.example.downloadtest.providers.DownloadManager.Request;  
  31. import com.example.downloadtest.providers.downloads.Downloads;  
  32.   
  33. public class MainActivity extends Activity {  
  34.   
  35.     public static final String TAG = MainActivity.class.getSimpleName();  
  36.     private static final int QUERY_DOWNLOAD_PROGRESS = 10;  
  37.     private static final String DOWNLOAD_DIR_NAME = "test_download";  
  38.     private DownloadManager mDownloadManager;  
  39.     private ListView mListView;  
  40.     private MyContentObserver mContentObserver = new MyContentObserver();  
  41.     private List<AppInfo> downloadList = new ArrayList<AppInfo>();  
  42.     private DownloadAdapter mAdapter;  
  43.     private MyApplication mApp;  
  44.   
  45.     private Handler handler = new Handler() {  
  46.         public void handleMessage(android.os.Message msg) {  
  47.             switch (msg.what) {  
  48.             case QUERY_DOWNLOAD_PROGRESS:  
  49.   
  50.                 if (mAdapter != null) {  
  51.                     mAdapter.notifyDataSetChanged();  
  52.                 }  
  53.   
  54.                 break;  
  55.   
  56.             default:  
  57.                 break;  
  58.             }  
  59.         };  
  60.     };  
  61.   
  62.     @Override  
  63.     protected void onCreate(Bundle savedInstanceState) {  
  64.         super.onCreate(savedInstanceState);  
  65.         setContentView(R.layout.activity_main);  
  66.   
  67.         mDownloadManager = new DownloadManager(getContentResolver(),  
  68.                 getPackageName());  
  69.   
  70.         mApp = (MyApplication) getApplication();  
  71.   
  72.         initDownloadData();  
  73.         findView();  
  74.   
  75.         handleDownloadsChanged(); // 默认初始化  
  76.     }  
  77.   
  78.     @Override  
  79.     protected void onStart() {  
  80.   
  81.         getContentResolver().registerContentObserver(Downloads.CONTENT_URI,  
  82.                 true, mContentObserver);  
  83.   
  84.         super.onStart();  
  85.     }  
  86.   
  87.     @Override  
  88.     protected void onStop() {  
  89.   
  90.         getContentResolver().unregisterContentObserver(mContentObserver);  
  91.   
  92.         super.onStop();  
  93.     }  
  94.   
  95.     public void handleDownloadsChanged() {  
  96.   
  97.         DownloadManager.Query baseQuery = new DownloadManager.Query()  
  98.                 .setOnlyIncludeVisibleInDownloadsUi(true);  
  99.   
  100.         Cursor cursor = mDownloadManager.query(baseQuery);  
  101.   
  102.         int mIdColumnId = cursor  
  103.                 .getColumnIndexOrThrow(DownloadManager.COLUMN_ID);  
  104.   
  105.         int mStatusColumnId = cursor  
  106.                 .getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS);  
  107.         int mTotalBytesColumnId = cursor  
  108.                 .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);  
  109.         int mCurrentBytesColumnId = cursor  
  110.                 .getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);  
  111.   
  112.         while (cursor.moveToNext()) {  
  113.   
  114.             long downloadId = cursor.getLong(mIdColumnId);  
  115.             long totalBytes = cursor.getLong(mTotalBytesColumnId);  
  116.             long currentBytes = cursor.getLong(mCurrentBytesColumnId);  
  117.             int status = cursor.getInt(mStatusColumnId);  
  118.   
  119.             int progress = getProgressValue(totalBytes, currentBytes);  
  120.   
  121.             DownloadItem di = mApp.downloadMap  
  122.                     .get(mApp.mapping.get(downloadId));  
  123.   
  124.             if (di != null) {  
  125.                 di.setDownloadId(downloadId);  
  126.                 di.setTotalBytes(totalBytes);  
  127.                 di.setCurrentBytes(currentBytes);  
  128.                 di.setStatus(status);  
  129.                 di.setProgress(progress);  
  130.             }  
  131.         }  
  132.         cursor.close();  
  133.   
  134.         handler.sendEmptyMessage(QUERY_DOWNLOAD_PROGRESS);  
  135.     }  
  136.   
  137.     public int getProgressValue(long totalBytes, long currentBytes) {  
  138.         if (totalBytes == -1) {  
  139.             return 0;  
  140.         }  
  141.         return (int) (currentBytes * 100 / totalBytes);  
  142.     }  
  143.   
  144.     private void findView() {  
  145.   
  146.         mListView = (ListView) findViewById(R.id.mListView);  
  147.         mAdapter = new DownloadAdapter(getApplicationContext());  
  148.   
  149.         mListView.setAdapter(mAdapter);  
  150.     }  
  151.   
  152.     private void initDownloadData() {  
  153.   
  154.         String[] names = { "易信""百度地图""天天动听""网易新闻""电话帮""墨迹天气""生活日历",  
  155.                 "豆果美食" };  
  156.         String[] urls = {  
  157.                 "http://gdown.baidu.com/data/wisegame/653346a13ab69081/yixin_146.apk",  
  158.                 "http://gdown.baidu.com/data/wisegame/824ed743d6cdbbb6/baiduditu_431.apk",  
  159.                 "http://gdown.baidu.com/data/wisegame/839ca8c2da93e9e8/tiantiandongting_5902.apk",  
  160.                 "http://gdown.baidu.com/data/wisegame/8cafd2fb933d5c09/NetEaseNews_273.apk",  
  161.                 "http://www.yulore.com/go/?id=30",  
  162.                 "http://gdown.baidu.com/data/wisegame/2fdcb550af198691/mojitianqi_24402.apk",  
  163.                 "http://gdown.baidu.com/data/wisegame/0a3e9a0575a77fe2/shenghuorili_19.apk",  
  164.                 "http://gdown.baidu.com/data/wisegame/e61ab2327372efdf/DouguoRecipe_80.apk" };  
  165.         String[] infos = { "32万人安装 . 16.0MB""4182万人安装 . 10.5MB",  
  166.                 "4493万人安装 . 7.9MB""1148万人安装 . 6.1MB""21万人安装 . 3.1MB",  
  167.                 "8000万人安装 . 8.1MB""100万人安装 . 6.1MB""500万人安装 . 8.6MB" };  
  168.   
  169.         for (int i = 0; i < names.length; i++) {  
  170.   
  171.             String name = names[i];  
  172.             String url = urls[i];  
  173.   
  174.             AppInfo info = new AppInfo();  
  175.             info.setId("1000" + i);  
  176.             info.setName(name);  
  177.             info.setUrl(url);  
  178.             info.setInfo(infos[i]);  
  179.   
  180.             downloadList.add(info);  
  181.         }  
  182.     }  
  183.   
  184.     private class MyContentObserver extends ContentObserver {  
  185.   
  186.         public MyContentObserver() {  
  187.             super(new Handler());  
  188.         }  
  189.   
  190.         @Override  
  191.         public void onChange(boolean selfChange) {  
  192.   
  193.             handleDownloadsChanged();  
  194.   
  195.         }  
  196.     }  
  197.   
  198.     private long startDownload(AppInfo ai) {  
  199.   
  200.         //判断SD卡是否可用  
  201.         if(!checkSDCardIsAvailable()){  
  202.             Toast.makeText(getApplicationContext(), "外部存储空间不可用,请检查后再试", Toast.LENGTH_LONG).show();  
  203.             return -1;  
  204.         }  
  205.         try {  
  206.             String url = ai.getUrl();  
  207.   
  208.             Log.e(TAG, "download url:" + url);  
  209.   
  210.             Uri srcUri = Uri.parse(url);  
  211.             DownloadManager.Request request = new Request(srcUri);  
  212.   
  213.             // 设置文件保存的路径  
  214. //          request.setDestinationInExternalDir(getApplicationContext(),  
  215. //                  DOWNLOAD_DIR_NAME, ai.getName() + ".apk");  
  216.             request.setDestinationInExternalFilesDir(getApplicationContext(), DOWNLOAD_DIR_NAME, "");  
  217.             request.setDescription("下载");  
  218.   
  219.             return mDownloadManager.enqueue(request);  
  220.   
  221.         } catch (Exception e) {  
  222.             e.printStackTrace();  
  223.         }  
  224.         return -1;  
  225.     }  
  226.       
  227.     /** 
  228.      * 判断 SDCard是否可用 
  229.      *  
  230.      * @return 
  231.      */  
  232.     public boolean checkSDCardIsAvailable() {  
  233.         if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))  
  234.             return true;  
  235.         else  
  236.             return false;  
  237.     }  
  238.   
  239.     private class DownloadAdapter extends BaseAdapter {  
  240.   
  241.         private Context ctx;  
  242.         private LayoutInflater inflater;  
  243.   
  244.         public DownloadAdapter(Context ctx) {  
  245.             this.ctx = ctx;  
  246.             inflater = LayoutInflater.from(ctx);  
  247.         }  
  248.   
  249.         @Override  
  250.         public int getCount() {  
  251.   
  252.             return downloadList.size();  
  253.         }  
  254.   
  255.         @Override  
  256.         public Object getItem(int position) {  
  257.             // TODO Auto-generated method stub  
  258.             return downloadList.get(position);  
  259.         }  
  260.   
  261.         @Override  
  262.         public long getItemId(int position) {  
  263.             // TODO Auto-generated method stub  
  264.             return position;  
  265.         }  
  266.   
  267.         @Override  
  268.         public View getView(final int position, View convertView,  
  269.                 ViewGroup parent) {  
  270.   
  271.             View view;  
  272.             ViewHolder holder;  
  273.             if (convertView == null) {  
  274.   
  275.                 view = inflater.inflate(R.layout.download_item, null);  
  276.   
  277.                 holder = new ViewHolder();  
  278.                 holder.tv_app_name = (TextView) view  
  279.                         .findViewById(R.id.tv_app_name);  
  280.                 holder.tv_app_info = (TextView) view  
  281.                         .findViewById(R.id.tv_app_info);  
  282.                 holder.tv_progress_percent = (TextView) view  
  283.                         .findViewById(R.id.tv_progress_percent);  
  284.                 holder.bt_app_download = (Button) view.findViewById(R.id.bt_app_download);  
  285.   
  286.                 holder.pb_download_progress = (ProgressBar) view  
  287.                         .findViewById(R.id.pb_download_progress);  
  288.   
  289.                 view.setTag(holder);  
  290.             } else {  
  291.                 view = convertView;  
  292.                 holder = (ViewHolder) view.getTag();  
  293.             }  
  294.   
  295.             AppInfo ai = downloadList.get(position);  
  296.   
  297.             holder.tv_app_name.setText(ai.getName());  
  298.             holder.tv_app_info.setText(ai.getInfo());  
  299.             holder.bt_app_download.setText(R.string.download);  
  300.   
  301.             final DownloadItem di = mApp.downloadMap.get(ai.getId());  
  302.   
  303.             if (di != null) {  
  304.   
  305.                 int status = di.getStatus();  
  306.   
  307.                 switch (status) {  
  308.                 case DownloadManager.STATUS_FAILED:  
  309.   
  310.                     Toast.makeText(ctx,  
  311.                             "下载 " + ai.getName() + " 失败,请检查网络之后重试",  
  312.                             Toast.LENGTH_LONG).show();  
  313.   
  314.                     holder.pb_download_progress.setVisibility(View.GONE);  
  315.                     holder.tv_progress_percent.setVisibility(View.GONE);  
  316.   
  317.                     mApp.mapping.remove(di.getDownloadId());// 删除  
  318.                     mApp.downloadMap.remove(ai.getId());// 删除  
  319.   
  320.                     // mDownloadManager.remove(downloadId);  
  321.                     mDownloadManager.markRowDeleted(di.getDownloadId()); // 删除该下载  
  322.   
  323.                     holder.bt_app_download.setText(R.string.failed);  
  324.   
  325.                     holder.tv_app_info.setVisibility(View.VISIBLE);  
  326.   
  327.                     break;  
  328.                 case DownloadManager.STATUS_SUCCESSFUL:  
  329.   
  330.                     Log.i(TAG, "download complete " + di.getDownloadId());  
  331.   
  332.                     holder.pb_download_progress.setVisibility(View.GONE);  
  333.                     holder.tv_progress_percent.setVisibility(View.GONE);  
  334.   
  335.                     mApp.mapping.remove(di.getDownloadId());// 删除  
  336.                     mApp.downloadMap.remove(ai.getId());// 删除  
  337.   
  338.                     holder.bt_app_download.setText(R.string.complete);  
  339.                     holder.tv_app_info.setVisibility(View.VISIBLE);  
  340.   
  341.                     break;  
  342.                 case DownloadManager.STATUS_PENDING:  
  343.                     holder.tv_progress_percent.setVisibility(View.VISIBLE);  
  344.                     holder.pb_download_progress.setVisibility(View.VISIBLE);  
  345.                     holder.tv_app_info.setVisibility(View.GONE);  
  346.   
  347.                     holder.tv_progress_percent.setText(R.string.pending);  
  348.   
  349.                     holder.bt_app_download.setText(R.string.cancel);  
  350.                       
  351.                     break;  
  352.                 case DownloadManager.STATUS_RUNNING:  
  353.   
  354.                     holder.tv_progress_percent.setVisibility(View.VISIBLE);  
  355.                     holder.pb_download_progress.setVisibility(View.VISIBLE);  
  356.                     holder.tv_app_info.setVisibility(View.GONE);  
  357.   
  358.                     int progress = di.getProgress();  
  359.   
  360.                     holder.pb_download_progress.setProgress(progress);  
  361.                     holder.tv_progress_percent.setText(progress + "%");  
  362.   
  363.                     break;  
  364.                 case DownloadManager.STATUS_PAUSED:  
  365.                     holder.tv_progress_percent.setVisibility(View.VISIBLE);  
  366.                     holder.pb_download_progress.setVisibility(View.VISIBLE);  
  367.                     holder.tv_app_info.setVisibility(View.GONE);  
  368.   
  369.                     holder.bt_app_download.setText(R.string.resume);  
  370.                     break;  
  371.                 default:  
  372.                     break;  
  373.                 }  
  374.   
  375.             } else {  
  376.                 holder.tv_progress_percent.setVisibility(View.GONE);  
  377.                 holder.pb_download_progress.setVisibility(View.GONE);  
  378.                 holder.tv_app_info.setVisibility(View.VISIBLE);  
  379.             }  
  380.   
  381.             holder.bt_app_download.setOnClickListener(new OnClickListener() {  
  382.   
  383.                 @Override  
  384.                 public void onClick(View v) {  
  385.   
  386.                     Button bt = (Button) v;  
  387.                     AppInfo info = downloadList.get(position);  
  388.                     DownloadItem di = mApp.downloadMap.get(info.getId());  
  389.   
  390.                     String str = bt.getText().toString();  
  391.   
  392.                     if ("下载".equals(str)) {  
  393.   
  394.                         long downloadId = startDownload(info);  
  395.   
  396.                         if (downloadId != -1) {  
  397.                             DownloadItem downloadItem = new DownloadItem();  
  398.                             downloadItem.setDownloadId(downloadId);  
  399.                             downloadItem.setId(info.getId());  
  400.   
  401.                             mApp.downloadMap.put(info.getId(), downloadItem);  
  402.                             mApp.mapping.put(downloadId, info.getId());  
  403.                         }  
  404.   
  405.                     } else if ("暂停".equals(str)) {  
  406.   
  407.                         if (di != null && (di.getStatus() == DownloadManager.STATUS_RUNNING)) {  
  408.                             mDownloadManager.pauseDownload(di.getDownloadId());  
  409.                         }  
  410.   
  411.                     } else if ("继续".equals(str)) {  
  412.   
  413.                         if (di != null && (di.getStatus() == DownloadManager.STATUS_PAUSED)) {  
  414.                             mDownloadManager.resumeDownload(di.getDownloadId());  
  415.                         }  
  416.                     } else if ("取消".equals(str)) {  
  417.   
  418.                         if (di != null && (di.getStatus() == DownloadManager.STATUS_PENDING)) {  
  419.                             mDownloadManager.markRowDeleted(di.getDownloadId());  
  420.                         }  
  421.                     }  
  422.   
  423.                     notifyDataSetChanged(); // 刷新  
  424.                 }  
  425.             });  
  426.   
  427.             return view;  
  428.         }  
  429.     }  
  430.   
  431.     static class ViewHolder {  
  432.         public TextView tv_app_name;  
  433.         public TextView tv_app_info;  
  434.         public TextView tv_progress_percent;  
  435.         public Button bt_app_download;  
  436.         public ProgressBar pb_download_progress;  
  437.     }  
  438. }  



MyApplication.java

[java] view plaincopy
  1. package com.example.downloadtest.app;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.Map;  
  5.   
  6. import android.app.Application;  
  7. import android.content.Intent;  
  8.   
  9. import com.example.downloadtest.entity.DownloadItem;  
  10. import com.example.downloadtest.providers.downloads.DownloadService;  
  11.   
  12. public class MyApplication extends Application {  
  13.       
  14.     public Map<String,DownloadItem> downloadMap = new HashMap<String,DownloadItem>();   //key AppInfo id,value 下载进度信息  
  15.     public Map<Long,String> mapping = new HashMap<Long, String>();  //key downloadId,value AppInfo id  
  16.       
  17.     @Override  
  18.     public void onCreate() {  
  19.   
  20.         startDownloadService();  
  21.           
  22.         super.onCreate();  
  23.     }  
  24.   
  25.     private void startDownloadService() {  
  26.         Intent intent = new Intent();  
  27.         intent.setClass(this, DownloadService.class);  
  28.         startService(intent);  
  29.     }  
  30. }  


 



工程下载地址:http://download.csdn.net/detail/fx_sky/6419647





0 0
原创粉丝点击