1、首先我们设置Dialog的 布局文件,download_dialog.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/colorPrimary"
android:text="版本更新"/>
<ProgressBar
android:id="@+id/mProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"/>
<TextView
android:id="@+id/mTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/colorPrimary"
android:text="0%"/>
</LinearLayout>
2、
进度条显示下载进度,TextView显示下载百分比。
然后自定义一个AlertDialog,将布局文件设置进去,DownloadDialog.java :
public class DownloadDialog extends AlertDialog {
private Context mContext;
private TextView mTextView;
private ProgressBar mProgressBar;
private View view;
protected DownloadDialog(Context context) {
super(context);
this.mContext = context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置对话框样式
setStyle();
//初始化控件
initView();
}
private void initView() {
view = View.inflate(mContext,R.layout.dwonlaod_dialog,null);
mTextView = (TextView)view.findViewById(R.id.mTextView);
mProgressBar = (ProgressBar)view.findViewById(R.id.mProgressBar);
setContentView(view);
}
private void setStyle() {
//设置对话框不可取消
this.setCancelable(false);
//设置触摸对话框外面不可取消
this.setCanceledOnTouchOutside(false);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindow().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
//获得应用窗口大小
WindowManager.LayoutParams layoutParams = this.getWindow().getAttributes();
//设置对话框居中显示
layoutParams.gravity = Gravity.CENTER;
//设置对话框宽度为屏幕的3/5
layoutParams.width = (displaymetrics.widthPixels/5)*3;
}
//设置进度条
public void setProgress(int progress){
mTextView.setText(progress+"%");
mProgressBar.setProgress(progress);
}
}
3、创建显示对话框,取消对话框的方法,MainActivity :
private void showDialog() {
if(downloadDialog==null){
downloadDialog = new DownloadDialog(this);
}
if(!downloadDialog.isShowing()){
downloadDialog.show();
}
}
4、创建一个download方法用于下载应用:
private void download() {
showDialog();
//最好是用单线程池,或者intentService
new Thread(new DownLoadRunnable(this,url, handler)).start();
}
5、DownloadRunnable中的具体处理方法:
public class DownLoadRunnable implements Runnable {
private String url;
private Handler handler;
private Context mContext;
public DownLoadRunnable(Context context, String url, Handler handler) {
this.mContext = context;
this.url = url;
this.handler = handler;
}
@Override
public void run() {
//设置线程优先级为后台,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//具体下载方法
startDownload();
}
private long startDownload() {
//获得DownloadManager对象
DownloadManager downloadManager=(DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
//获得下载id,这是下载任务生成时的唯一id,可通过此id获得下载信息
long requestId= downloadManager.enqueue(CreateRequest(url));
//查询下载信息方法
queryDownloadProgress(requestId,downloadManager);
return requestId;
}
private void queryDownloadProgress(long requestId, DownloadManager downloadManager) {
DownloadManager.Query query=new DownloadManager.Query();
//根据任务编号id查询下载任务信息
query.setFilterById(requestId);
try {
boolean isGoging=true;
while (isGoging) {
Cursor cursor = downloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
//获得下载状态
int state = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (state) {
case DownloadManager.STATUS_SUCCESSFUL://下载成功
isGoging=false;
handler.obtainMessage(downloadManager.STATUS_SUCCESSFUL).sendToTarget();//发送到主线程,更新ui
break;
case DownloadManager.STATUS_FAILED://下载失败
isGoging=false;
handler.obtainMessage(downloadManager.STATUS_FAILED).sendToTarget();//发送到主线程,更新ui
break;
case DownloadManager.STATUS_RUNNING://下载中
/**
* 计算下载下载率;
*/
int totalSize = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
int currentSize = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
int progress = (int) (((float) currentSize) / ((float) totalSize) * 100);
handler.obtainMessage(downloadManager.STATUS_RUNNING, progress).sendToTarget();//发送到主线程,更新ui
break;
case DownloadManager.STATUS_PAUSED://下载停止
handler.obtainMessage(DownloadManager.STATUS_PAUSED).sendToTarget();
break;
case DownloadManager.STATUS_PENDING://准备下载
handler.obtainMessage(DownloadManager.STATUS_PENDING).sendToTarget();
break;
}
}
if(cursor!=null){
cursor.close();
}
}
}catch (Exception e){
e.printStackTrace();
}
}
private DownloadManager.Request CreateRequest(String url) {
DownloadManager.Request request=new DownloadManager.Request(Uri.parse(url));
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);// 隐藏notification
request.setAllowedNetworkTypes(request.NETWORK_WIFI);//设置下载网络环境为wifi
request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS,"MyApp.app");//指定apk缓存路径,默认是在SD卡中的Download文件夹
return request;
}
}
6、在主线程中通过Handler获取Message,并回调handleMessage方法处理信息,更新UI,MainActivity.java:
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case DownloadManager.STATUS_SUCCESSFUL:
downloadDialog.setProgress(100);
canceledDialog();
Toast.makeText(MainActivity.this, "下载任务已经完成!", Toast.LENGTH_SHORT).show();
break;
case DownloadManager.STATUS_RUNNING:
//int progress = (int) msg.obj;
downloadDialog.setProgress((int) msg.obj);
//canceledDialog();
break;
case DownloadManager.STATUS_FAILED:
canceledDialog();
break;
case DownloadManager.STATUS_PENDING:
showDialog();
break;
}
}
};
7、下载完成后进行安装(静态注册广播接收器,实现安装功能)AndroidManifest.xml:
<receiver
android:name=".InstallApkBroadcast">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
</intent-filter>
</receiver>
8、接受广播并自行安装应用,InstallApkBroadcast.java:
public class InstallApkBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
install(context);
}
private void install(Context context) {
Intent installintent = new Intent();
installintent.setAction(Intent.ACTION_VIEW);
// 在Boradcast中启动活动需要添加Intent.FLAG_ACTIVITY_NEW_TASK
installintent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// installintent.setDataAndType(
// Uri.fromFile(new File(Environment.getExternalStorageDirectory()
// + "/vc.apk")),
// "application/vnd.android.package-archive");// 存储位置为Android/data/包名/file/Download文件夹
installintent.setDataAndType(
Uri.fromFile(new File(context.getExternalFilesDir(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
+ "/vc.apk")),
"application/vnd.android.package-archive");
context.startActivity(installintent);
}
}
9、权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
参考: