您的位置:首页 > 移动开发

Android中的app升级逻辑(非热更新)

2017-03-06 15:43 190 查看
最近新接手的项目中出现了很多的bug,全部要重头实现,这个过程我也感慨良多,一个良好的代码书写习惯和严谨的逻辑思维习惯真的是一个程序员必备的

条件和因素,如果一个程序员自己的写的代码自己后期都看不懂,那么怎样才能保证项目的长期稳定的代码性呢?今天给大家分享的这个升级的逻辑就是经过

我的整理之后的,如果有不严谨的地方请大家多多批评斧正!

首先贴上一张我自己用xmind画的app冷升级的逻辑构图



好的,大家从上面的思维导图中也可以很清楚的看到我的升级逻辑思维,那么我们现在直接从代码逻辑中进行说明(相关的逻辑说明我已经添加了很详细的注释)

/**
* ===================================================
* 方法作者:wkzhao on 2017年3月6日16:01:34
* 方法描述: 访问更新的接口进行升级的逻辑方法
* 作者邮箱:wkzhao@iflytek.com
* ===================================================
*/
private void httpUpDate() {
JsonObject object = new JsonObject();
/**
* String.valueOf(CommUtils.getAppVersionCode(this))
* 将int类型的versioncode更改成string类型的versioncode
* 解决后台协调的参数类型不一致的问题 接口参数应该为int类
* 型 但是参数设置错误设置成string类型
*/
object.addProperty("currentVersionCode", String.valueOf(CommUtils.getAppVersionCode(this)));
object.addProperty("mobileType", "0");
object.addProperty("currentVersionName", CommUtils.getAppVersionName(this));

//开始网络请求 获得接口获得返回值
new HttpUtils().httpRequest(this, CFZXProperties.CHECKUPDATE_GETNEWVERSION, object, new HttpInterface() {

//请求网络接口成功的回调
@Override
public void success(ResponseData response) {
if (response.getStatus().equals("0")) {
return;
}
BaseResp baseUpDateResp = JsonUtil.fromJson(response.getResult(), BaseResp.class);
if (baseUpDateResp == null) {
return;
}

//对请求结果进行判断 根据结果决定是否更新
if (baseUpDateResp.isFlag()){
//json解析获取到的数据
final CheckUpDate checkUpDate = JsonUtil.fromJson(baseUpDateResp.getData().toString(), CheckUpDate.class);
/**
* VersionCode:程序员使用的版本号为int类型的数值 在本项目中进行比较所采用的基准值
* VersionName:用户显示采用的版本号为String类型的数值 在本项目中是用来进行显示的基准值
* 获取线上版本号VersionCode
*/
int netVersionCode = checkUpDate.getVersionCode();
Log.e("netVersionCode","线上版本号是:" + netVersionCode);
//获取本地版本号
int localVersionCode = CommUtils.getVersionCode(HomeActivity.this);
Log.e("localVersionCode","本地版本号是:" + localVersionCode);
if (localVersionCode < netVersionCode){
isForceUpdate = checkUpDate.getForcedUpdate();
//需要更新 判断是否为强制升级
if (isForceUpdate == 1){
/**
* 强制升级 把是否是强制升级的isForceUpdate作为参数传递给
* ChickUpDateDialog 在ChickUpDateDialog中进行判断如果
* 是强制升级  那么在点击忽略的时候直接退出app 如果不是强制
* 升级那么直接走一普通的升级逻辑可以点击忽略以后仍然打开app
*/
chickUpDateDialog = new ChickUpDateDialog(
HomeActivity.this,
checkUpDate.getVersionSize().toString(),
checkUpDate.getPath().toString(),
checkUpDate.getVersionDescribe(),
checkUpDate.getVersionName(),1);
chickUpDateDialog.show();
//不需要强制升级
}else if (isForceUpdate == 0){
chickUpDateDialog = new ChickUpDateDialog(
HomeActivity.this,
checkUpDate.getVersionSize().toString(),
checkUpDate.getPath().toString(),
checkUpDate.getVersionDescribe(),
checkUpDate.getVersionName(),0);
chickUpDateDialog.show();
}

}else{
//不需要更新
com.iflytek.credit.utils.BaseToast.showToast(HomeActivity.this, "当前已经是最新版本了");
}

}else{
//接口请求获取到的数值错误
Log.e("updateInterfaceMsg",SysCode.ERROR_NAME.UPDATE_INTERFACE_ERROR);
}
}

//请求网络接口失败的回调
@Override
public void onError(VolleyError volleyError) {
Log.e("updateInterfaceMsg",SysCode.ERROR_NAME.UPDATE_INTERFACE_APPLY_ERROR);
}
});
}


在访问结果处理中的ChickUpdateDialog是我自己封装的一个弹框工具类,下面可以直接贴出代码,供大家参考

/**
* ==========================================
* 作者:wkzhao on 2017年3月6日16:03:46
* 类注释:更新的弹出框工具类
* 邮箱:wkzhao@iflytek.com
* ==========================================
*/
public class ChickUpDateDialog extends BaseDialog {

private Context context;

private Button btnChickCancel;//关闭
private Button btnChickOpen;//打开

private DownUpDateDialog downUpDateDialog;
private String appSize;
private String url;
private String des;
private String v;//版本
private int isForceUpdate;
private TextView tv_show_new;
private TextView tv_chick_des;
private TextView tv_version;
private TextView tv_update_desc;

public ChickUpDateDialog(Context context,String appSize,String url,String des,String v,int isForceUpdate) {
super(context, R.style.MY_Dialog_Style);
this.context = context;
this.appSize = appSize;
this.url = url;
this.des = des;
this.v = v;
this.isForceUpdate = isForceUpdate;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState,R.layout.dialog_update_new);
}

@Override
public void initBoots() {
downUpDateDialog = new DownUpDateDialog(context,url);
}

@Override
public void initViews() {
//提示信息
tv_show_new = (TextView) findViewById(R.id.tv_show_new);
//消耗流量
tv_chick_des = (TextView) findViewById(R.id.tv_chick_des);
//版本号
tv_version = (TextView) findViewById(R.id.update_dialog_version_content);
//更新版本的详细描述
tv_update_desc = (TextView) findViewById( R.id.update_dialog_vdesc);
//取消按钮
btnChickCancel = (Button) findViewById(R.id.btn_chick_cancel);
//确定按钮
btnChickOpen = (Button) findViewById(R.id.btn_chick_open);
}

@Override
public void initData() {
if (isForceUpdate == 1){
tv_show_new.setText("有版本更新(强制升级)");
}else if(isForceUpdate == 0){
tv_show_new.setText("有版本更新");
}
tv_chick_des.setText(appSize + "MB");
tv_version.setText("V" + v);
tv_update_desc.setText(des);

}

@Override
public void initEvents() {
//取消按钮
btnChickCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isForceUpdate == 1){
dismiss();
System.exit(0);
}else if (isForceUpdate == 0){
dismiss();
}

}
});

//打开按钮
btnChickOpen.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
downUpDateDialog.show();
}
});
}
}


在这个类中的DownUpdateDialog是封装的另一个工具类,代码如下:

/**
* ==========================================
* 作者:wkzhao on 2017年3月6日16:06:34
* 类注释:更新弹框工具类
* 邮箱:wkzhao@iflytek.com
* ==========================================
*/
public class DownUpDateDialog extends BaseDialog {
/*控件*/
private TextView tvDownCount;//下载的百分之几的提示
private Button btnDownCancel;//关闭的按钮
private Button btnDownOpen;//打开的按钮
private ProgressBar pbDown;//下载进度条

private Context context;
private String url;//下载地址

private int lastRate = 0;//进度的初始值
private InputStream is = null;//输入流
private FileOutputStream fos = null;//文件输出流

/* 下载包安装路径 */
private static final String savePath = FunctionUtility.getUpgradePath();//获得手机的根路径
private static final String saveFileName = savePath + "changfeng.apk";//存储的文件名
private String apkUrl;//apk的下载地址
private int progress;//进度条
boolean canceled;//是否关闭下载
private Thread downLoadThread;//下载的线程

public DownUpDateDialog(Context context,String url) {
super(context, R.style.MY_Dialog_Style);
this.context = context;
this.url = url;
this.apkUrl = url;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState,R.layout.dialog_down_update);
}

@Override
public void initBoots() {

}

@Override
public void initViews() {
tvDownCount = (TextView) findViewById(R.id.tv_down_count);
btnDownCancel = (Button) findViewById(R.id.btn_down_cancel);
btnDownOpen = (Button) findViewById(R.id.btn_down_open);
pbDown = (ProgressBar) findViewById(R.id.pb_down_progressbar);
}

@Override
public void initData() {
btnDownOpen.setClickable(false);//还没下载结束的时候先要设置打开按钮式不可点击的
progress = 0;

//开启线程开始下载
new Thread() {
public void run() {
// 开始下载
startDownload();
};
}.start();
}

@Override
public void initEvents() {
//关闭
btnDownCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//关闭下载服务,并且推出
dismiss();
}
});

//打开下载的软件安装
btnDownOpen.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
installApk();//安装
dismiss();
}
});
}
private void startDownload() {
canceled = false;
downloadApk();
}

/**
* 下载apk
*
* @param
*/
private void downloadApk() {
downLoadThread = new Thread(mdownApkRunnable);
downLoadThread.start();
}

/**
* 安装apk
*
* @param
*/
private void installApk() {
File apkfile = new File(saveFileName);
if (!apkfile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
context.startActivity(i);
}
private Runnable mdownApkRunnable = new Runnable() {

@Override
public void run() {
try {
URL url = new URL(apkUrl);//下载的链接地址
HttpURLConnection conn = (HttpURLConnection) url.openConnection();//创建链接
conn.connect();
int length = conn.getContentLength();//获得长度
is = conn.getInputStream();//转化成流的形式

File file = new File(savePath);//文件的存放位置(存放的文件夹)
//判断文件夹是否是存在的
if (!file.exists()) {
file.mkdirs();//如果不存在则创建文件夹
}
String apkFile = saveFileName;//存储的apk的名字
File ApkFile = new File(apkFile);
fos = new FileOutputStream(ApkFile);//转化成输出流

int count = 0;
byte buf[] = new byte[1024];

do {
int numread = is.read(buf);
count += numread;
progress = (int) (((float) count / length) * 100);
// 更新进度
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = progress;
//判断什么时候停止,更新进度条
if (progress >= lastRate + 1) {
mHandler.sendMessage(msg);
lastRate = progress;
}
//判断什么时候是现在完成
if (numread <= 0) {
mHandler.sendEmptyMessage(0);// 下载完成通知安装
// 下载完了,cancelled也要设置
canceled = true;
break;
}
fos.write(buf, 0, numread);
} while (!canceled);// 点击取消就停止下载.
//Log.i("DownApkService----------canceled", canceled + "");
fos.close();
is.close();
} catch (Exception e) {

Message msg = mHandler.obtainMessage();
msg.what = 3;
mHandler.sendMessage(msg);
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
is.close();
if (is != null) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}

}
};

private Handler mHandler = new Handler() {

@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
// 下载完毕
// 取消通知
// mNotificationManager.cancel(NOTIFY_ID);
//设置打开按钮可以点击
btnDownOpen.setClickable(true);
btnDownOpen.setBackgroundResource(R.mipmap.icon_dialog_btn_sure);
btnDownOpen.setTextColor(Color.parseColor("#ffffff"));
break;
case 2:
dismiss();
break;
case 1:
int rate = msg.arg1;
if (rate < 100) {
tvDownCount.setText("已完成"+rate+"%");
pbDown.setProgress(rate);
} else {
tvDownCount.setText("已完成"+100+"%");
pbDown.setProgress(100);
}
break;
case 3:
break;

}
}
};


以上就是我封装的全部的更新逻辑,现在app升级的逻辑除了热更新,以上应该是最齐全的工具类了,欢迎大家阅读

我是IT老王,热爱编程,热爱生活!!!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息