android各系统中,formatter适配

Android 中,格式化文件大小(Formatter.formatFileSize),Android8 之前用 1024 为单位,之后采用 1000 为单位。

Formatter 的源码解析

查看 Android 28(Android P)源码

1
2
3
4
5
6
7
8
9
10
11
12
13
public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
final int unit = ((flags & FLAG_IEC_UNITS) != 0) ? 1024 : 1000;
final boolean isNegative = (sizeBytes < 0);
float result = isNegative ? -sizeBytes : sizeBytes;
int suffix = com.android.internal.R.string.byteShort;
long mult = 1;
if (result > 900) {
suffix = com.android.internal.R.string.kilobyteShort;
mult = unit;
result = result / unit;
}
......
}

formatFileSize 方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 /* <p>As of O, the prefixes are used in their standard meanings in the SI system, so kB = 1000
* bytes, MB = 1,000,000 bytes, etc.</p>
*
* <p class="note">In {@link android.os.Build.VERSION_CODES#N} and earlier, powers of 1024 are
* used instead, with KB = 1024 bytes, MB = 1,048,576 bytes, etc.</p>
*/
public static String formatFileSize(@Nullable Context context, long sizeBytes) {
if (context == null) {
return "";
}
final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SI_UNITS);
return bidiWrap(context, context.getString(com.android.internal.R.string.fileSizeSuffix,
res.value, res.units));
}

意思就是在 Android 7 之后单位就变了,使用标准的单位制含义,即国际单位制,就像 1km = 1000 byte 一样;
在 Android 7 及更早的版本是 1024,即 1k = 1024B,这里就不贴代码了,感兴趣的同学可以去看源码。

解决方案

有两个方案,一个是反射设置 FLAG_SI_UNITS 的值,使得与 FLAG_IEC_UNITS 相与不为 0 ,
另外一个方案重新封装一个类,如下,用法与 Android 提供的一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Formatter {
/** * get file format size * * @param context context * @param roundedBytes file size * @return file format size (like 2.12k) */
public static String formatFileSize(Context context, long roundedBytes) {
return formatFileSize(context, roundedBytes, false, Locale.US);
}

public static String formatFileSize(Context context, long roundedBytes, Locale locale) {
return formatFileSize(context, roundedBytes, false, locale);
}


private static String formatFileSize(Context context, long roundedBytes, boolean shorter, Locale locale) {
if (context == null) {
return "";
}
float result = roundedBytes;
String suffix = "B";
if (result > 900) {
suffix = "KB";
result = result / 1024;
}
if (result > 900) {
suffix = "MB";
result = result / 1024;
}
if (result > 900) {
suffix = "GB";
result = result / 1024;
}
if (result > 900) {
suffix = "TB";
result = result / 1024;
}
if (result > 900) {
suffix = "PB";
result = result / 1024;
}
String value;
if (result < 1) {
value = String.format(locale, "%.2f", result);
} else if (result < 10) {
if (shorter) {
value = String.format(locale, "%.1f", result);
} else {
value = String.format(locale, "%.2f", result);
}
} else if (result < 100) {
if (shorter) {
value = String.format(locale, "%.0f", result);
} else {
value = String.format(locale, "%.2f", result);
}
} else {
value = String.format(locale, "%.0f", result);
}
return String.format("%s%s", value, suffix);
}

}