就Android本身而言,其实大可不必比较字符版本号,Android系统本身升级应用的时候,也是由versionCode来判定版本大小的,而不是versionName。
defaultConfig {
applicationId "com.xter.test"
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.targetSdkVersion
versionCode 1
versionName "0.72"
flavorDimensions "versionCode"
buildConfigField("boolean", "LOG", "true")
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
然而出于某种考虑(也许是兼容其他平台比如服务端的版本号?),字符版本号还是用得相当多,那么更新的时候,就得把新老版本号拿出来比较了。
- 方法一:转成long值比较
- 方法二:比较字符串每位字符的char值即ASCII码大小
- 方法三:直接使用compareTo方法
方法一
说出来自己都吓一跳,强迫症首先想到的是把字符串统一成数字来比较大小。
public static boolean compareVersion1(String version1, String version2) {
String version1Number = version1.replace(".", "");
String version2Number = version2.replace(".", "");
if (version1Number.length() != version2Number.length()) {
//长度不一,则按长度长者末尾补0
if (version2Number.length() > version1Number.length()) {
version1Number = version1Number + String.format(Locale.CHINA, "%" +
(version2Number.length() - version1Number.length()) + "d", 0);
} else {
version2Number = version2Number + String.format(Locale.CHINA, "%" +
(version1Number.length() - version2Number.length()) + "d", 0);
}
}
return Long.parseLong(version2Number) > Long.parseLong(version1Number);
}
想法很简洁,然而写出来就是这么一大坨…
又是去掉”."分隔符,又是补0,又是转long值…
并且,当你的版本号是这种“1.23.456.7890.1234567890“很长长度的时候,就不能比较了,为什么?因为long没有这么大…
Long.MAX_VALUE = 9223372036854775807
long的最大值都只有19位数,所以这种方法最好在版本号数字长度小于19的情况下使用。
或者把版本号拆成几段再转long值比较?
算了,不折腾了…
方法二
比较每一位的字符ASCII码大小,这样就避免了去除"."分隔符了,只要字符相同,ASCII码肯定是一样的,而数字较大,ASCII值也是较大的,那岂不是…
美滋滋?
当然还是要考虑两者长度不一样的情况。
public static boolean compareVersion2(String version1, String version2) {
int lenMin = version1.length() < version2.length() ? version1.length() : version2.length();
//两者差异值,此处是version2对versoin1
int offset = 0;
for (int i = 0; i < lenMin; i++) {
offset = offset + version2.charAt(i) - version1.charAt(i);
//若在高位已有差异,则跳出
if (offset != 0) {
break;
}
}
if (offset == 0) {
//若高位无差异,则长度大者更大
offset = version2.length() - version1.length();
}
return offset > 0;
}
果然美滋滋。
char和int值本就可以直接做运算(因为在JVM编译期间,boolean/byte/char/short都会扩展为相应的int类型数据)。
如果可以想到这个方法,其实已经够用了。
方法三
为什么会想到方法三?因为如果读过一点源码,肯定会觉得方法二的逻辑似曾相识…
先看下方法三的代码:
public static boolean compareVersion3(String version1, String version2) {
if (version2.compareTo(version1) > 0) {
return true;
}
return false;
}
短小!
精悍!
为什么可以起作用?看compareTo的源码:
//String.java
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
没有错,compareTo方法就是用的方法二,所以说如果想到了第二种方法,已经足够了,当然如果熟悉已有的API就更好了。
最后附上一段测试代码:
public static void main(String[] args) {
String versoin1_1 = "1.4.5";
String version1_2 = "1.4.6";
System.out.println(compareVersion1(versoin1_1, version1_2));
System.out.println(compareVersion2(versoin1_1, version1_2));
System.out.println(compareVersion3(versoin1_1, version1_2));
String version2_1 = "1.2.3";
String version2_2 = "1.2";
System.out.println(compareVersion1(version2_1, version2_2));
System.out.println(compareVersion2(version2_1, version2_2));
System.out.println(compareVersion3(version2_1, version2_2));
String version3_1 = "1.8.4";
String version3_2 = "1.9";
System.out.println(compareVersion1(version3_1, version3_2));
System.out.println(compareVersion2(version3_1, version3_2));
System.out.println(compareVersion3(version3_1, version3_2));
String version4_1 = "1.5.0";
String version4_2 = "1.4.9.9";
System.out.println(compareVersion1(version4_1, version4_2));
System.out.println(compareVersion2(version4_1, version4_2));
System.out.println(compareVersion3(version4_1, version4_2));
String version5_1 = "0.72";
String version5_2 = "0.719";
System.out.println(compareVersion1(version5_1, version5_2));
System.out.println(compareVersion2(version5_1, version5_2));
System.out.println(compareVersion3(version5_1, version5_2));
String version6_1 = "1.5.1111.543";
String version6_2 = "1.5.1112.534";
System.out.println(compareVersion1(version6_1, version6_2));
System.out.println(compareVersion2(version6_1, version6_2));
System.out.println(compareVersion3(version6_1, version6_2));
}
以上。