这个页面的功能有:基本的显示加载的logo页面,logo页面会有一些文本的信息,版本号版本名等信息。加载的时候,会保持logo页面至少2秒(睡眠的方式来实现)。进入的时候会判断一下当前的版本和服务端获取的json的版本信息,如果服务端的版本号大于现在的版本号会进行升级,同时splash页面会现在下载的进度等等信息。下载完成以后用户可以选择安装或者取消安装跳转首页,或者直接返回不安装跳转首页。
获取版本信息
/**
* 获取版本的版本名
*/
private String getVersionName() {
// 获取到包的管理器
PackageManager packagerManager = getPackageManager();
try {
// 获取包名
PackageInfo packageInfo = packagerManager.getPackageInfo(
getPackageName(), 0);
// 版本号
int versionCode = packageInfo.versionCode;
// 版本名
String versionName = packageInfo.versionName;
System.out.println("versionName:" + versionName);
return versionName;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
/**
* 获取版本的版本号
*/
private int getVersionCode() {
// 获取到包的管理器
PackageManager packagerManager = getPackageManager();
try {
// 获取包名
PackageInfo packageInfo = packagerManager.getPackageInfo(
getPackageName(), 0);
// 版本号
int versionCode = packageInfo.versionCode;
// 版本名
String versionName = packageInfo.versionName;
System.out.println("versionCode:" + versionCode);
return versionCode;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
下载版本,通过子线程的方式来进行下载,防止阻塞主线程,利用Handle消息队列机制来根据不同的消息来加载
/**
* 从服务器获取版本信息校验,确定是否需要进行升级
*/
private void checkVersion() {
// 获取当前的时间
final long startTime = System.currentTimeMillis();
// 防止阻塞主线程
new Thread() {
@Override
public void run() {
String path = "http://192.168.0.100:8080/update.json";
Message msg = Message.obtain();
HttpURLConnection conn = null;
try {
URL url = new URL(path);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");// 请求方式
conn.setConnectTimeout(5000);// 链接超时
conn.setReadTimeout(5000);// 响应超时,连接成功,但服务器不给响应
conn.connect();// 链接服务器
int responseCode = conn.getResponseCode();// 获取响应码
if (responseCode == 200) {
InputStream inputStream = conn.getInputStream();
String result = StreamUtils
.readFromeStream(inputStream);
System.out.println("返回的结果是:" + result);
// 解析json,作者的版本鸡西不了json,因此设置成固定值,正常应该是解析出来的值,注释下面5行
/*
* 解析不了json为了测试,写成固定值 JSONObject jo = new
* JSONObject(result); mVersionName =
* jo.getString("versionName"); mVersionCode =
* jo.getInt("VersionCode"); mDesc =
* jo.getString("description"); mDownloadUrl =
* jo.getString("downloadUrl");
*/
JSONObject jo = new JSONObject(result);
mVersionName = "2.0";
mVersionCode = 2;
mDesc = "赶紧升级啊";
mDownloadUrl = "http://192.168.0.100:8080/Safe2.0.apk";
System.out.println("添加的功能:" + mDesc);
if (mVersionCode > getVersionCode()) {
// 服务器的版本号大于本地的版本号,需要升级
// 需要升级,弹出升级对话框
msg.what = CODE_UPDATE_DIALOG;
} else {
// 没有版本更新,跳转主页
msg.what = CODE_ENTER_HOME;
}
}
} catch (MalformedURLException e) {
// 更新异常
msg.what = CODE_UPDATE_ERROR;
e.printStackTrace();
} catch (IOException e) {
// 网络异常
msg.what = CODE_NET_ERROR;
e.printStackTrace();
} catch (JSONException e) {
// JSON异常
msg.what = CODE_JSON_ERROR;
e.printStackTrace();
} finally {
// 强制logo界面加载显示2s
long endTime = System.currentTimeMillis();
long timeUsed = endTime - startTime;
if (timeUsed < 2000) {
try {
Thread.sleep(2000 - timeUsed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 主线程发消息
mHandler.sendMessage(msg);
// 关闭网络连接
if (conn != null) {
conn.disconnect();
}
}
}
}.start();
}
消息队列的处理
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CODE_UPDATE_DIALOG:
showUpdate();
break;
case CODE_UPDATE_ERROR:
Toast.makeText(SplashActivity.this, "升级错误", Toast.LENGTH_SHORT)
.show();
// 跳转主页面
enterHome();
break;
case CODE_NET_ERROR:
Toast.makeText(SplashActivity.this, "网络错误", Toast.LENGTH_SHORT)
.show();
// 跳转主页面
enterHome();
break;
case CODE_JSON_ERROR:
Toast.makeText(SplashActivity.this, "JSON数据解析错误",
Toast.LENGTH_SHORT).show();
// 跳转主页面
enterHome();
break;
case CODE_ENTER_HOME:
// 跳转主页面
enterHome();
break;
default:
break;
}
}
};
下载apk和安装apk的方法
/**
* 下载新版的apk
*/
protected void download() {
// 先判断有没有sd卡
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 下载的时候让进度显示
tv_progress.setVisibility(View.VISIBLE);
// 文件下载的位置
String target = Environment.getExternalStorageDirectory()
+ "/UPDATE.APK";
// 利用github的Xutils执行下载
HttpUtils utils = new HttpUtils();
utils.download(mDownloadUrl, target, new RequestCallBack<File>() {
@Override
public void onLoading(long total, long current,
boolean isUploading) {
super.onLoading(total, current, isUploading);
System.out.println("下载进度" + current + "/" + total);
tv_progress.setText("下载进度:" + current * 100 / total + "%");
}
// 下载失败
@Override
public void onFailure(HttpException arg0, String arg1) {
Toast.makeText(SplashActivity.this, "下载失败",
Toast.LENGTH_SHORT).show();
}
// 下载成功
@Override
public void onSuccess(ResponseInfo<File> arg0) {
System.out.println("下载成功");
// 跳转到系统的下载页面
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(arg0.result),
"application/vnd.android.package-archive");
// startActivity(intent);
startActivityForResult(intent, 0);// 如果用户取消安装,会返回结果,会调用发onActivityResult
}
});
} else {
Toast.makeText(SplashActivity.this, "没有sd卡", Toast.LENGTH_SHORT)
.show();
}
}
在安装界面,用户可能点击返回,处理如下
/**
* 防止用户在升级界面按下返回按键
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
enterHome();
super.onActivityResult(requestCode, resultCode, data);
}
总代码如下:
package com.ldw.safe.Activity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.ldw.safe.R;
import com.ldw.safe.db.dao.AntiVirous;
import com.ldw.safe.utils.StreamUtils;
import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;
import com.lidroid.xutils.http.client.HttpRequest.HttpMethod;
public class SplashActivity extends Activity {
protected static final int CODE_UPDATE_DIALOG = 0;
protected static final int CODE_UPDATE_ERROR = 1;
protected static final int CODE_NET_ERROR = 2;
protected static final int CODE_JSON_ERROR = 3;
protected static final int CODE_ENTER_HOME = 4;
private TextView tv_version;
private TextView tv_progress;// 下载进度显示
// 服务器json参数
private String mVersionName;
private int mVersionCode;
private String mDesc;
private String mDownloadUrl;
private SharedPreferences mPref;//把设置的数据保存在mPref
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CODE_UPDATE_DIALOG:
showUpdate();
break;
case CODE_UPDATE_ERROR:
Toast.makeText(SplashActivity.this, "升级错误", Toast.LENGTH_SHORT)
.show();
// 跳转主页面
enterHome();
break;
case CODE_NET_ERROR:
Toast.makeText(SplashActivity.this, "网络错误", Toast.LENGTH_SHORT)
.show();
// 跳转主页面
enterHome();
break;
case CODE_JSON_ERROR:
Toast.makeText(SplashActivity.this, "JSON数据解析错误",
Toast.LENGTH_SHORT).show();
// 跳转主页面
enterHome();
break;
case CODE_ENTER_HOME:
// 跳转主页面
enterHome();
break;
default:
break;
}
}
};
private RelativeLayout splash;
private AntiVirous virous;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// 显示版本号
TextView tv_version = (TextView) findViewById(R.id.tv_version);
tv_version.setText("版本号:" + getVersionName());
// 下载进度显示,默认是隐藏的
tv_progress = (TextView) findViewById(R.id.tv_progress);
//获取splsh的全局属性
splash = (RelativeLayout)findViewById(R.id.splash);
mPref = getSharedPreferences("config", MODE_PRIVATE);
copyDB("address.db");//拷贝数据库
copyDB("antivirus.db");//拷贝病毒库
//更新病毒库
updateVirous();
//检测设置是否设置了自动更新
boolean autoUpdate = mPref.getBoolean("auto_update", true);
if(autoUpdate){
checkVersion();
}else{
//不自动升级
mHandler.sendEmptyMessageDelayed(CODE_ENTER_HOME, 2000);//延迟2s进入主页
}
//让splash页面有一个渐变的效果
AlphaAnimation anim = new AlphaAnimation(0.3f, 1f);
anim.setDuration(2000);
splash.startAnimation(anim);
}
/*
* 更新病毒数据库
*/
private void updateVirous() {
virous = new AntiVirous();
//联网从服务器获取到最新数据的md5的特征码
HttpUtils httpUtils = new HttpUtils();
//新增的病毒库
String url = "http://192.168.0.2:8080/virus.json";
httpUtils.send(HttpMethod.GET, url, new RequestCallBack<String>() {
@Override
public void onFailure(HttpException arg0, String arg1) {
// TODO Auto-generated method stub
}
@Override
public void onSuccess(ResponseInfo<String> arg0) {
//解析json
try {
JSONObject jsonObject = new JSONObject(arg0.result);
/*
谷歌的gojosn
Gson gson = new Gson();
//解析json
Virus virus = gson.fromJson(arg0.result, Virus.class);
dao.addVirus(virus.md5, virus.desc);
*/
//json的key-value配对{}
String md5 = jsonObject.getString("md5");
String desc = jsonObject.getString("desc");
virous.addVirous(md5, desc);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
/**
* 获取版本的版本名
*/
private String getVersionName() {
// 获取到包的管理器
PackageManager packagerManager = getPackageManager();
try {
// 获取包名
PackageInfo packageInfo = packagerManager.getPackageInfo(
getPackageName(), 0);
// 版本号
int versionCode = packageInfo.versionCode;
// 版本名
String versionName = packageInfo.versionName;
System.out.println("versionName:" + versionName);
return versionName;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
/**
* 获取版本的版本号
*/
private int getVersionCode() {
// 获取到包的管理器
PackageManager packagerManager = getPackageManager();
try {
// 获取包名
PackageInfo packageInfo = packagerManager.getPackageInfo(
getPackageName(), 0);
// 版本号
int versionCode = packageInfo.versionCode;
// 版本名
String versionName = packageInfo.versionName;
System.out.println("versionCode:" + versionCode);
return versionCode;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
/**
* 从服务器获取版本信息校验,确定是否需要进行升级
*/
private void checkVersion() {
// 获取当前的时间
final long startTime = System.currentTimeMillis();
// 防止阻塞主线程
new Thread() {
@Override
public void run() {
String path = "http://192.168.0.100:8080/update.json";
Message msg = Message.obtain();
HttpURLConnection conn = null;
try {
URL url = new URL(path);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");// 请求方式
conn.setConnectTimeout(5000);// 链接超时
conn.setReadTimeout(5000);// 响应超时,连接成功,但服务器不给响应
conn.connect();// 链接服务器
int responseCode = conn.getResponseCode();// 获取响应码
if (responseCode == 200) {
InputStream inputStream = conn.getInputStream();
String result = StreamUtils
.readFromeStream(inputStream);
System.out.println("返回的结果是:" + result);
// 解析json,作者的版本鸡西不了json,因此设置成固定值,正常应该是解析出来的值,注释下面5行
/*
* 解析不了json为了测试,写成固定值 JSONObject jo = new
* JSONObject(result); mVersionName =
* jo.getString("versionName"); mVersionCode =
* jo.getInt("VersionCode"); mDesc =
* jo.getString("description"); mDownloadUrl =
* jo.getString("downloadUrl");
*/
JSONObject jo = new JSONObject(result);
mVersionName = "2.0";
mVersionCode = 2;
mDesc = "赶紧升级啊";
mDownloadUrl = "http://192.168.0.100:8080/Safe2.0.apk";
System.out.println("添加的功能:" + mDesc);
if (mVersionCode > getVersionCode()) {
// 服务器的版本号大于本地的版本号,需要升级
// 需要升级,弹出升级对话框
msg.what = CODE_UPDATE_DIALOG;
} else {
// 没有版本更新,跳转主页
msg.what = CODE_ENTER_HOME;
}
}
} catch (MalformedURLException e) {
// 更新异常
msg.what = CODE_UPDATE_ERROR;
e.printStackTrace();
} catch (IOException e) {
// 网络异常
msg.what = CODE_NET_ERROR;
e.printStackTrace();
} catch (JSONException e) {
// JSON异常
msg.what = CODE_JSON_ERROR;
e.printStackTrace();
} finally {
// 强制logo界面加载显示2s
long endTime = System.currentTimeMillis();
long timeUsed = endTime - startTime;
if (timeUsed < 2000) {
try {
Thread.sleep(2000 - timeUsed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 主线程发消息
mHandler.sendMessage(msg);
// 关闭网络连接
if (conn != null) {
conn.disconnect();
}
}
}
}.start();
}
/**
* 弹出升级对话框
*/
private void showUpdate() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("最新版本:" + mVersionName);
builder.setMessage(mDesc);
// builder.setCancelable(false);//在升级页面不允许返回,这种方法不可取
builder.setPositiveButton("立即更新", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 下载新版的apk
download();
}
});
builder.setNegativeButton("稍后更新", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 用户不升级直接跳转到主页
enterHome();
}
});
// 监听升级页面,用户按下返回按键,直接跳到主界面
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
enterHome();
}
});
builder.show();
}
/**
* 下载新版的apk
*/
protected void download() {
// 先判断有没有sd卡
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 下载的时候让进度显示
tv_progress.setVisibility(View.VISIBLE);
// 文件下载的位置
String target = Environment.getExternalStorageDirectory()
+ "/UPDATE.APK";
// 利用github的Xutils执行下载
HttpUtils utils = new HttpUtils();
utils.download(mDownloadUrl, target, new RequestCallBack<File>() {
@Override
public void onLoading(long total, long current,
boolean isUploading) {
super.onLoading(total, current, isUploading);
System.out.println("下载进度" + current + "/" + total);
tv_progress.setText("下载进度:" + current * 100 / total + "%");
}
// 下载失败
@Override
public void onFailure(HttpException arg0, String arg1) {
Toast.makeText(SplashActivity.this, "下载失败",
Toast.LENGTH_SHORT).show();
}
// 下载成功
@Override
public void onSuccess(ResponseInfo<File> arg0) {
System.out.println("下载成功");
// 跳转到系统的下载页面
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setDataAndType(Uri.fromFile(arg0.result),
"application/vnd.android.package-archive");
// startActivity(intent);
startActivityForResult(intent, 0);// 如果用户取消安装,会返回结果,会调用发onActivityResult
}
});
} else {
Toast.makeText(SplashActivity.this, "没有sd卡", Toast.LENGTH_SHORT)
.show();
}
}
/**
* 防止用户在升级界面按下返回按键
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
enterHome();
super.onActivityResult(requestCode, resultCode, data);
}
/**
* 进入主页面
*/
public void enterHome() {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
}
/*
* 拷贝数据库
*/
public void copyDB(String dbName){
//获取数据库的文件路径,要拷贝的目标地址
File targetFile = new File(getFilesDir(), dbName);//
//数据库存在
if(targetFile.exists()){
System.out.println("数据库已经存在");
return;
}
FileOutputStream out = null;
InputStream in = null;
try {
in = getAssets().open(dbName);
out = new FileOutputStream(targetFile);
//读数据
int len = 0;
byte[] buffer = new byte[1024];
while((len = in.read(buffer)) != -1 ){
out.write(buffer, 0, len);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
in.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}