这里使用的是github上的一个开源项目 DownloadProvider 下载地址:https://github.com/yxl/DownloadProvider,支持多线程下载和断点续传功能,自己在它上面作了一些修改以满足业务需求。
先看效果图吧:
通知栏下载进度 提示
工程目录结构如下:
清单文件
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.downloadtest"
- android:versionCode="1"
- android:versionName="1.0" >
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="17" />
- <!-- Allows access to the Download Manager -->
- <permission
- android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER"
- android:description="@string/permdesc_downloadManager"
- android:label="@string/permlab_downloadManager"
- android:protectionLevel="normal" />
- <!-- Allows advanced access to the Download Manager -->
- <permission
- android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED"
- android:description="@string/permdesc_downloadManagerAdvanced"
- android:label="@string/permlab_downloadManagerAdvanced"
- android:protectionLevel="normal" />
- <!-- Allows to send broadcasts on download completion -->
- <permission
- android:name="com.example.downloadtest.permission.SEND_DOWNLOAD_COMPLETED_INTENTS"
- android:description="@string/permdesc_downloadCompletedIntent"
- android:label="@string/permlab_downloadCompletedIntent"
- android:protectionLevel="normal" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER" />
- <uses-permission android:name="com.example.downloadtest.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED" />
- <uses-permission android:name="com.example.downloadtest.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@style/AppTheme" android:name=".app.MyApplication">
- <activity
- android:name="com.example.downloadtest.MainActivity"
- android:label="@string/app_name" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <provider
- android:name="com.example.downloadtest.providers.downloads.DownloadProvider"
- android:authorities="com.example.downloadtest.downloads" android:exported="false"/>
- <service android:name="com.example.downloadtest.providers.downloads.DownloadService" />
- <receiver
- android:name="com.example.downloadtest.providers.downloads.DownloadReceiver"
- android:exported="false" >
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
- </intent-filter>
- </receiver>
- </application>
- </manifest>
界面布局文件 activity_main.xml
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity" >
- <ListView
- android:id="@+id/mListView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:cacheColorHint="@android:color/transparent"/>
- </RelativeLayout>
MainActivity.java
- package com.example.downloadtest;
- import java.util.ArrayList;
- import java.util.List;
- import android.app.Activity;
- import android.content.Context;
- import android.database.ContentObserver;
- import android.database.Cursor;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.Button;
- import android.widget.ListView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.example.downloadtest.app.MyApplication;
- import com.example.downloadtest.entity.AppInfo;
- import com.example.downloadtest.entity.DownloadItem;
- import com.example.downloadtest.providers.DownloadManager;
- import com.example.downloadtest.providers.DownloadManager.Request;
- import com.example.downloadtest.providers.downloads.Downloads;
- public class MainActivity extends Activity {
- public static final String TAG = MainActivity.class.getSimpleName();
- private static final int QUERY_DOWNLOAD_PROGRESS = 10;
- private static final String DOWNLOAD_DIR_NAME = "test_download";
- private DownloadManager mDownloadManager;
- private ListView mListView;
- private MyContentObserver mContentObserver = new MyContentObserver();
- private List<AppInfo> downloadList = new ArrayList<AppInfo>();
- private DownloadAdapter mAdapter;
- private MyApplication mApp;
- private Handler handler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case QUERY_DOWNLOAD_PROGRESS:
- if (mAdapter != null) {
- mAdapter.notifyDataSetChanged();
- }
- break;
- default:
- break;
- }
- };
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mDownloadManager = new DownloadManager(getContentResolver(),
- getPackageName());
- mApp = (MyApplication) getApplication();
- initDownloadData();
- findView();
- handleDownloadsChanged(); // 默认初始化
- }
- @Override
- protected void onStart() {
- getContentResolver().registerContentObserver(Downloads.CONTENT_URI,
- true, mContentObserver);
- super.onStart();
- }
- @Override
- protected void onStop() {
- getContentResolver().unregisterContentObserver(mContentObserver);
- super.onStop();
- }
- public void handleDownloadsChanged() {
- DownloadManager.Query baseQuery = new DownloadManager.Query()
- .setOnlyIncludeVisibleInDownloadsUi(true);
- Cursor cursor = mDownloadManager.query(baseQuery);
- int mIdColumnId = cursor
- .getColumnIndexOrThrow(DownloadManager.COLUMN_ID);
- int mStatusColumnId = cursor
- .getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS);
- int mTotalBytesColumnId = cursor
- .getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
- int mCurrentBytesColumnId = cursor
- .getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
- while (cursor.moveToNext()) {
- long downloadId = cursor.getLong(mIdColumnId);
- long totalBytes = cursor.getLong(mTotalBytesColumnId);
- long currentBytes = cursor.getLong(mCurrentBytesColumnId);
- int status = cursor.getInt(mStatusColumnId);
- int progress = getProgressValue(totalBytes, currentBytes);
- DownloadItem di = mApp.downloadMap
- .get(mApp.mapping.get(downloadId));
- if (di != null) {
- di.setDownloadId(downloadId);
- di.setTotalBytes(totalBytes);
- di.setCurrentBytes(currentBytes);
- di.setStatus(status);
- di.setProgress(progress);
- }
- }
- cursor.close();
- handler.sendEmptyMessage(QUERY_DOWNLOAD_PROGRESS);
- }
- public int getProgressValue(long totalBytes, long currentBytes) {
- if (totalBytes == -1) {
- return 0;
- }
- return (int) (currentBytes * 100 / totalBytes);
- }
- private void findView() {
- mListView = (ListView) findViewById(R.id.mListView);
- mAdapter = new DownloadAdapter(getApplicationContext());
- mListView.setAdapter(mAdapter);
- }
- private void initDownloadData() {
- String[] names = { "易信", "百度地图", "天天动听", "网易新闻", "电话帮", "墨迹天气", "生活日历",
- "豆果美食" };
- String[] urls = {
- "http://gdown.baidu.com/data/wisegame/653346a13ab69081/yixin_146.apk",
- "http://gdown.baidu.com/data/wisegame/824ed743d6cdbbb6/baiduditu_431.apk",
- "http://gdown.baidu.com/data/wisegame/839ca8c2da93e9e8/tiantiandongting_5902.apk",
- "http://gdown.baidu.com/data/wisegame/8cafd2fb933d5c09/NetEaseNews_273.apk",
- "http://www.yulore.com/go/?id=30",
- "http://gdown.baidu.com/data/wisegame/2fdcb550af198691/mojitianqi_24402.apk",
- "http://gdown.baidu.com/data/wisegame/0a3e9a0575a77fe2/shenghuorili_19.apk",
- "http://gdown.baidu.com/data/wisegame/e61ab2327372efdf/DouguoRecipe_80.apk" };
- String[] infos = { "32万人安装 . 16.0MB", "4182万人安装 . 10.5MB",
- "4493万人安装 . 7.9MB", "1148万人安装 . 6.1MB", "21万人安装 . 3.1MB",
- "8000万人安装 . 8.1MB", "100万人安装 . 6.1MB", "500万人安装 . 8.6MB" };
- for (int i = 0; i < names.length; i++) {
- String name = names[i];
- String url = urls[i];
- AppInfo info = new AppInfo();
- info.setId("1000" + i);
- info.setName(name);
- info.setUrl(url);
- info.setInfo(infos[i]);
- downloadList.add(info);
- }
- }
- private class MyContentObserver extends ContentObserver {
- public MyContentObserver() {
- super(new Handler());
- }
- @Override
- public void onChange(boolean selfChange) {
- handleDownloadsChanged();
- }
- }
- private long startDownload(AppInfo ai) {
- //判断SD卡是否可用
- if(!checkSDCardIsAvailable()){
- Toast.makeText(getApplicationContext(), "外部存储空间不可用,请检查后再试", Toast.LENGTH_LONG).show();
- return -1;
- }
- try {
- String url = ai.getUrl();
- Log.e(TAG, "download url:" + url);
- Uri srcUri = Uri.parse(url);
- DownloadManager.Request request = new Request(srcUri);
- // 设置文件保存的路径
- // request.setDestinationInExternalDir(getApplicationContext(),
- // DOWNLOAD_DIR_NAME, ai.getName() + ".apk");
- request.setDestinationInExternalFilesDir(getApplicationContext(), DOWNLOAD_DIR_NAME, "");
- request.setDescription("下载");
- return mDownloadManager.enqueue(request);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return -1;
- }
- /**
- * 判断 SDCard是否可用
- *
- * @return
- */
- public boolean checkSDCardIsAvailable() {
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
- return true;
- else
- return false;
- }
- private class DownloadAdapter extends BaseAdapter {
- private Context ctx;
- private LayoutInflater inflater;
- public DownloadAdapter(Context ctx) {
- this.ctx = ctx;
- inflater = LayoutInflater.from(ctx);
- }
- @Override
- public int getCount() {
- return downloadList.size();
- }
- @Override
- public Object getItem(int position) {
- // TODO Auto-generated method stub
- return downloadList.get(position);
- }
- @Override
- public long getItemId(int position) {
- // TODO Auto-generated method stub
- return position;
- }
- @Override
- public View getView(final int position, View convertView,
- ViewGroup parent) {
- View view;
- ViewHolder holder;
- if (convertView == null) {
- view = inflater.inflate(R.layout.download_item, null);
- holder = new ViewHolder();
- holder.tv_app_name = (TextView) view
- .findViewById(R.id.tv_app_name);
- holder.tv_app_info = (TextView) view
- .findViewById(R.id.tv_app_info);
- holder.tv_progress_percent = (TextView) view
- .findViewById(R.id.tv_progress_percent);
- holder.bt_app_download = (Button) view.findViewById(R.id.bt_app_download);
- holder.pb_download_progress = (ProgressBar) view
- .findViewById(R.id.pb_download_progress);
- view.setTag(holder);
- } else {
- view = convertView;
- holder = (ViewHolder) view.getTag();
- }
- AppInfo ai = downloadList.get(position);
- holder.tv_app_name.setText(ai.getName());
- holder.tv_app_info.setText(ai.getInfo());
- holder.bt_app_download.setText(R.string.download);
- final DownloadItem di = mApp.downloadMap.get(ai.getId());
- if (di != null) {
- int status = di.getStatus();
- switch (status) {
- case DownloadManager.STATUS_FAILED:
- Toast.makeText(ctx,
- "下载 " + ai.getName() + " 失败,请检查网络之后重试",
- Toast.LENGTH_LONG).show();
- holder.pb_download_progress.setVisibility(View.GONE);
- holder.tv_progress_percent.setVisibility(View.GONE);
- mApp.mapping.remove(di.getDownloadId());// 删除
- mApp.downloadMap.remove(ai.getId());// 删除
- // mDownloadManager.remove(downloadId);
- mDownloadManager.markRowDeleted(di.getDownloadId()); // 删除该下载
- holder.bt_app_download.setText(R.string.failed);
- holder.tv_app_info.setVisibility(View.VISIBLE);
- break;
- case DownloadManager.STATUS_SUCCESSFUL:
- Log.i(TAG, "download complete " + di.getDownloadId());
- holder.pb_download_progress.setVisibility(View.GONE);
- holder.tv_progress_percent.setVisibility(View.GONE);
- mApp.mapping.remove(di.getDownloadId());// 删除
- mApp.downloadMap.remove(ai.getId());// 删除
- holder.bt_app_download.setText(R.string.complete);
- holder.tv_app_info.setVisibility(View.VISIBLE);
- break;
- case DownloadManager.STATUS_PENDING:
- holder.tv_progress_percent.setVisibility(View.VISIBLE);
- holder.pb_download_progress.setVisibility(View.VISIBLE);
- holder.tv_app_info.setVisibility(View.GONE);
- holder.tv_progress_percent.setText(R.string.pending);
- holder.bt_app_download.setText(R.string.cancel);
- break;
- case DownloadManager.STATUS_RUNNING:
- holder.tv_progress_percent.setVisibility(View.VISIBLE);
- holder.pb_download_progress.setVisibility(View.VISIBLE);
- holder.tv_app_info.setVisibility(View.GONE);
- int progress = di.getProgress();
- holder.pb_download_progress.setProgress(progress);
- holder.tv_progress_percent.setText(progress + "%");
- break;
- case DownloadManager.STATUS_PAUSED:
- holder.tv_progress_percent.setVisibility(View.VISIBLE);
- holder.pb_download_progress.setVisibility(View.VISIBLE);
- holder.tv_app_info.setVisibility(View.GONE);
- holder.bt_app_download.setText(R.string.resume);
- break;
- default:
- break;
- }
- } else {
- holder.tv_progress_percent.setVisibility(View.GONE);
- holder.pb_download_progress.setVisibility(View.GONE);
- holder.tv_app_info.setVisibility(View.VISIBLE);
- }
- holder.bt_app_download.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Button bt = (Button) v;
- AppInfo info = downloadList.get(position);
- DownloadItem di = mApp.downloadMap.get(info.getId());
- String str = bt.getText().toString();
- if ("下载".equals(str)) {
- long downloadId = startDownload(info);
- if (downloadId != -1) {
- DownloadItem downloadItem = new DownloadItem();
- downloadItem.setDownloadId(downloadId);
- downloadItem.setId(info.getId());
- mApp.downloadMap.put(info.getId(), downloadItem);
- mApp.mapping.put(downloadId, info.getId());
- }
- } else if ("暂停".equals(str)) {
- if (di != null && (di.getStatus() == DownloadManager.STATUS_RUNNING)) {
- mDownloadManager.pauseDownload(di.getDownloadId());
- }
- } else if ("继续".equals(str)) {
- if (di != null && (di.getStatus() == DownloadManager.STATUS_PAUSED)) {
- mDownloadManager.resumeDownload(di.getDownloadId());
- }
- } else if ("取消".equals(str)) {
- if (di != null && (di.getStatus() == DownloadManager.STATUS_PENDING)) {
- mDownloadManager.markRowDeleted(di.getDownloadId());
- }
- }
- notifyDataSetChanged(); // 刷新
- }
- });
- return view;
- }
- }
- static class ViewHolder {
- public TextView tv_app_name;
- public TextView tv_app_info;
- public TextView tv_progress_percent;
- public Button bt_app_download;
- public ProgressBar pb_download_progress;
- }
- }
MyApplication.java
- package com.example.downloadtest.app;
- import java.util.HashMap;
- import java.util.Map;
- import android.app.Application;
- import android.content.Intent;
- import com.example.downloadtest.entity.DownloadItem;
- import com.example.downloadtest.providers.downloads.DownloadService;
- public class MyApplication extends Application {
- public Map<String,DownloadItem> downloadMap = new HashMap<String,DownloadItem>(); //key AppInfo id,value 下载进度信息
- public Map<Long,String> mapping = new HashMap<Long, String>(); //key downloadId,value AppInfo id
- @Override
- public void onCreate() {
- startDownloadService();
- super.onCreate();
- }
- private void startDownloadService() {
- Intent intent = new Intent();
- intent.setClass(this, DownloadService.class);
- startService(intent);
- }
- }
工程下载地址:http://download.csdn.net/detail/fx_sky/6419647