在Android 中如果请求网络,数据量小的时候,可以使用Volley 库,但是如果是下载数据非常大时,变的不可行了。这时我们可以使用Andoid 自带的 DownloadManager ,只要是api 9以上都可以用。网上也有很多例子,但是大部分都是放在Activity 中,这样带来很多的不便。当我们下载大文件时必须在这个界面。所以,我就根据网上的例子,自己改造了一下,把下载放在Service 中,用来下载apk 安装。
1、首先,拿到启动Service 时传过来的 下载Url , DownloadManager 下载后会发出一个广播,所以我们同时注册下载完成的广播;
Intent intent = new Intent(MainActivity.this, DownloadRecommdAppService.class); intent.putExtra(DownloadRecommdAppService.DOWNLOAD_URL, url); startService(intent);
2、因为 Service 也是运行在主线程中的,所以,我们把下载这些耗时的工作另开线程进行。
3、在广播中,通过判断下载的状态,如果下载成功,就启动安装apk, 同时停止 Service.
public class DownloadRecommdAppService extends Service{ public static final String DOWNLOAD_URL = "download_url"; public static final String DOWNLOAD_FOLDER_NAME = "download"; public static final String DOWNLOAD_FILE_NAME = "yxhuang.apk"; @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { String downloadUrl = intent.getExtras().getString(DOWNLOAD_URL); if (downloadUrl != null) { // 注册下载完成广播 DownloadCompleteReceiver completeReceiver = new DownloadCompleteReceiver(); registerReceiver(completeReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); // 下载 new Thread(new DownloadRunable(downloadUrl)).start(); } } return super.onStartCommand(intent, flags, startId); } // 下载 class DownloadRunable implements Runnable{ private String mDownloadUrl; public DownloadRunable(String url) { mDownloadUrl = url; } @Override public void run() { startDownload(); } // 开始下载 private void startDownload(){ File folder = Environment.getExternalStoragePublicDirectory(DOWNLOAD_FOLDER_NAME); if (!folder.exists() || !folder.isDirectory()) { folder.mkdirs(); } DownloadManager manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mDownloadUrl)); request.setMimeType("application/vnd.android.package-archive"); // 存储的目录 request.setDestinationInExternalPublicDir(DOWNLOAD_FOLDER_NAME, DOWNLOAD_FILE_NAME); // 设定只有在 WIFI 情况下才能下载 request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); request.setTitle("下载应用"); request.setVisibleInDownloadsUi(true); manager.enqueue(request); } } // 下载完成 class DownloadCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); if (intent.getAction() == DownloadManager.ACTION_DOWNLOAD_COMPLETE) { checkStatus(context, completeDownloadId); } } private void checkStatus(Context context,Long completeDownloadId){ DownloadManager mManager = (DownloadManager) context.getSystemService(Service.DOWNLOAD_SERVICE); DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(completeDownloadId); Cursor cursor = mManager.query(query); if (cursor.moveToFirst()) { int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)); switch (status) { case DownloadManager.STATUS_RUNNING: break; case DownloadManager.STATUS_SUCCESSFUL: Toast.makeText(context, "下载成功", Toast.LENGTH_SHORT).show(); String apkFilePath = new StringBuilder(Environment.getExternalStorageDirectory().getAbsolutePath()) .append(File.separator).append(DownloadRecommdAppService.DOWNLOAD_FOLDER_NAME).append(File.separator) .append(DownloadRecommdAppService.DOWNLOAD_FILE_NAME).toString(); installApk(context, apkFilePath); // 停止下载Service DownloadRecommdAppService.this.stopSelf(); break; default: break; } } cursor.close(); } // 安装APk private void installApk(Context context, String file) { File apkFile = new File(file); Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); context.startActivity(intent); } } }
关于 DownloadManager 详细的介绍,移步至 http://www.trinea.cn/android/android-downloadmanager/