.自动更新的功能在实际运用中还是比较常用到的。
本文参考了大神的博客,自己复制写了一个,加上了些注释,也许会更好理解吧。
原文地址:http://blog.csdn.net/Android_Tutor/article/details/7015986
首先需要获得访问网络和读写的权限
请在AndroidManifest.xml 添加以下代码
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
两个XML文件
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" android:id="@+id/layout">
<TextView android:text="下载功能演示" android:id="@+id/textView1"
android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
</LinearLayout>
updateprogress.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:text="正在下载,请稍等。。。" android:id="@+id/textView1"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#fff"></TextView>
<ProgressBar style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:id="@+id/progressBar1"></ProgressBar>
<TextView android:text="文件大小:" android:id="@+id/textView2"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#fff"></TextView>
</LinearLayout>
两个java文件
Hello_worldActivity.java
package com.ccav;
import com.fjep.R;
import android.app.Activity;
import android.os.Bundle;
public class Hello_worldActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
updateClass update=new updateClass(this);
update.checkUpdateInfo();
}
}
updateClass.java
package com.ccav;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import com.fjep.R;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
public class updateClass {
private Context mContext;
private boolean flag = false;
private ProgressBar progressBar;
// 需要下载的APK文件地址
private String apkUrl = "http://shouji.360.cn/360safesis/360MobileSafe_3.1.0.apk";
// SD卡的文件夹位置
private static final String savePath = "/sdcard/updatedemo/";
// APK在SD卡中的路径
private static final String saveFileName = savePath + "UpdateDemo.apk";
private int progress;
private static final int START = 1;
private static final int OVER = 0;
private int numread;
private Dialog downloadDialog;
private TextView textview;
// 构造函数
public updateClass(Context context) {
mContext = context;
}
// 检查update,在实际运用中需要有版本的判断,但是由于这个是基础案例演示,就没有写更新的版本判断代码,直接调用更新提示框。
public void checkUpdateInfo() {
showDialog();
}
// 所谓的更新提示框
private void showDialog() {
AlertDialog.Builder builder = new Builder(mContext);
builder.setIcon(R.drawable.happy).setTitle("亲,系统检测到更新,是否要更新呢?")
.setMessage("点击确定立刻升级")
.setPositiveButton("立马更新", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
updateApk();
}
}).setNegativeButton("以后再说", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 让提示框消失
dialog.dismiss();
}
}).create().show();
}
// 显示点击“立马升级”之后显示的对话框,显示下载进度。
protected void updateApk() {
AlertDialog.Builder builder = new Builder(mContext);
// 由于进度条是在另一个xml文件中,所以需要通过inflater方法来加载这个layout文件
LayoutInflater layout = LayoutInflater.from(mContext);
View v = layout.inflate(R.layout.updateprogress, null);
// 利用findViewById的方法找到进度条的ID,为后面的更新进度条做准备,这里需要注意的是需要指定View,也就是v一定需要添加否则findViewById会报错哦。
progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
textview = (TextView) v.findViewById(R.id.textView2);
builder.setTitle("正在更新文件").setView(v)
.setNegativeButton("取消更新", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 让提示框消失
dialog.dismiss();
// flag是一个bool型变量,这里起得作用是停止线程,因为如果没有停止线程,用户点击取消更新后,线程还在执行下载。
flag = true;
}
});
// 这里可以直接使用.create().show()两个方法来让提示框显示,这样看上去代码也会更加简洁些,但是我们需要实现让其下载完毕之后关闭显示下载进度进度条的那个提示窗口功能。
downloadDialog = builder.create();
downloadDialog.show();
// 开始下载apk
downloadAPK();
}
private void downloadAPK() {
// 新建一个线程
new Thread(new Runnable() {
@Override
public void run() {
try {
// 将下载路径赋值给url
URL url = new URL(apkUrl);
// http连接的方法
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.connect();
// 获得需要下载的文件长度
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
// 检查文件夹是否存在,不存在就创建该文件夹
File file = new File(savePath);
if (!file.exists()) {
file.mkdir();
}
FileOutputStream fos = new FileOutputStream(saveFileName);
int count = 0;
// 缓冲大小1024比较科学,如果太小下载速度很慢,即使你网速很快。
byte buf[] = new byte[1024];
do {
numread = is.read(buf);
count += numread;
// 这里获取进度条的进度,注意值的转换。
progress = (int) (((float) count / length) * 100);
// 发送消息让线程开始工作
myHandler.sendEmptyMessage(START);
if (numread <= 0) {
myHandler.sendEmptyMessage(OVER);
break;
}
// 写入APK文件
fos.write(buf, 0, numread);
} while (!flag);// 这里注意flag,是在flag不为true的情况下执行while循环。之前使用flag是在用户点击取消按钮的时候将flag设置为true,这样这个循环就被停止了,也就是线程不在发送消息给handler,同时也停止了下载工作
// 输入输出用完记得要关闭哦
fos.close();
is.close();
} catch (Exception e) {
Log.i("Fover", e.toString());
}
}
}).start();// 这里要记得start让线程开始工作
}
// Handler用于更新UI
private Handler myHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case START:
// 更新进度条的值
progressBar.setProgress(progress);
// 显示完成度
textview.setText("已完成" + progress + "%");
break;
case OVER:
// 让下载对话框消失
downloadDialog.dismiss();
// 安装下载好的APK文件
installApk();
break;
default:
break;
}
}
};
protected void installApk() {
// 如果这apk文件不存在,直接返回不执行后面的代码
File file = new File(saveFileName);
if (!file.exists()) {
return;
}
// 利用intent来启动安装
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://" + saveFileName.toString()),
"application/vnd.android.package-archive");
mContext.startActivity(i);
}
}
直接复制代码的同学,请注意R文件要和自己包里面的相同哦,要不然会报错。
运行截图:
PS我不是360的托,随便找个APK的地址文件。将就着用了。