最近遇到一个开发中的小问题,软件版本比较:例如2.12.3和2.2.1这两个版本号,哪个更新。
其实,客户端版本检测更新,检测后台是否有更新版本可更新,Java中最简单的一种方法便是获取当前客户端版本号,与服务端提供的最新版本号做equals对比即可。
假设当前客户端版本号为localVersion 后台提供最新客户端版本号为onlineVersion
通过if (localVersion.equals(onlineVersion))即可判断是否有新版本。这种判断只是比较本地版本号字符串和后台版本号是否完全一致来做判断的。但这存在一个问题,假如后台版本号比当前版本号低,localVersion.equals(onlineVersion)同样为true,这样就会引起一个问题,软件会被更新为比当前版本更低的版本,显然这不是我们所期望的。
那么如何避免这个问题呢,最好做版本号大小的判断。最初想到的一个方法便是把版本号转为double型数据再进行比较 比如版本号1.2.2便通过替换掉字符串中除第一个"."之外的所有"."再通过 Double.valueOf(String)方法转换为Double类型的值进行比较。用这种方法确实可以比较版本号的大小,比如版本号1.2.2和1.2.3便是比较1.22和1.23的大小,显然比较结果版本号1.2.3大于1.2.2,结果正确。
/**
* 判断是否为最新版本
*
* @param localVersion
* 本地版本号
* @param onlineVersion
* 线上版本号
*/
public static boolean isNewVersionDouble(String localVersion, String onlineVersion)
{
if (localVersion == null || onlineVersion == null)
{
return false;
}
return parseStrVersionCodeToDouble(onlineVersion).compareTo(parseStrVersionCodeToDouble(localVersion)) > 0 ? true
: false;
}
/**
* 将字符串型版本号转换为Double型版本号
*
* @param versionCode
* @return
*/
private static Double parseStrVersionCodeToDouble(String versionCode)
{
if (versionCode.contains("."))
{
String versionStr = versionCode.substring(0, versionCode.indexOf(".") + 1)
+ versionCode.substring(versionCode.indexOf(".") + 1).replace(".", "");
return Double.valueOf(versionStr);
}
else
{
return Double.valueOf(versionCode);
}
}
后来看到网上可以直接使用String.compareTO方法比较,便尝试了,直接让onlineVersion.compareTo(localVersion) 可以达到与转换为double类型比较相同的效果。
/**
* String.comparTo方法
*
* @param localVersion
* @param onlineVersion
* @return
*/
public static boolean isNewVersionStr(String localVersion, String onlineVersion)
{
if (localVersion == null || onlineVersion == null)
{
return false;
}
return onlineVersion.compareTo(localVersion) > 0 ? true : false;
}
但上述两个方法在比较两个点之间为单位数的版本号(例如2.2.1和2.3.1)时能返回正确结果,但在比较两个点之间不都为单位数版本号(如2.2.1和2.12.1)时便返回了错误的结果,显然版本号2.12.1要大于2.2.1但返回结果却恰恰相反。为什么呢?使用转换为double 比较方法时,实际比较的是2.21和2.121这两个数值的大小,显然2.21大于2.121,这个方法返回了错误的结果不难理解。而使用String.compareTo方法时实际是依次比较字符串各个字符的Unicode value大小,显然当比到第一个小数点后的值时2>1所以便得出了版本号2.2.1大于2.12.1的错误结果。
至此,我们可以得出一个结论,直接使用String.compareTo方法可以达到转换Double再比较相同的效果,因此,第一种转换double再比较的方法就没有了存在的意义,只是更麻烦点、更低效而已。但我们比较两点之间多位版本号的目的使用String.compareTo方法并不能实现。怎么比才能在任何情况下都返回正确结果呢。我想到的一个便是通过点切分版本号为数组在依次比较数组中各个值的大小,这样就不会出现比较中认为2比12大的情况。
/**
* 判断是否为最新版本方法 将版本号根据.切分为int数组 比较
*
* @param localVersion
* 本地版本号
* @param onlineVersion
* 线上版本号
* @return
*/
public static boolean isAppNewVersion(String localVersion, String onlineVersion)
{
if (localVersion.equals(onlineVersion))
{
return false;
}
String[] localArray = localVersion.split("\\.");
String[] onlineArray = onlineVersion.split("\\.");
int length = localArray.length < onlineArray.length ? localArray.length : onlineArray.length;
for (int i = 0; i < length; i++)
{
if (Integer.parseInt(onlineArray[i]) > Integer.parseInt(localArray[i]))
{
return true;
}
else if (Integer.parseInt(onlineArray[i]) < Integer.parseInt(localArray[i]))
{
return false;
}
// 相等 比较下一组值
}
return true;
}
最后一个方法便可在比较两点之间多位的版本号时返回正确的结果。有兴趣可以复制代码运行试试。
我暂时想到的解决方法便是这个,抛砖引玉,如果有更好的、更高效、简便的比较方法,请留言赐教,谢谢!