在Android开发或渠道分发场景中,我们经常需要根据一定的策略从多个包名中选择一个进行后续操作。例如,可能需要优先选择某些高优先级的应用,当这些应用不存在时,再从其他应用中随机选择。这样的需求看似简单,但实现起来需要考虑多种边界条件和优化策略。
本文将详细讲解如何实现一个智能的包名选择策略,包括:
我们需要实现一个方法,能够根据以下规则选择一个包名:
appList 为空,则从静态高优先级列表 HIGH_PRIORITY_PAG 随机选择一个。appList 不为空,检查它是否包含 HIGH_PRIORITY_PAG 中的包名: appList 中随机选一个。为了保证高优先级包名列表不可变,我们使用 Collections.unmodifiableList 或 Java 9+ 的 List.of 方法:
private static final List<String> HIGH_PRIORITY_PAG = Collections.unmodifiableList(
Arrays.asList(
"com.smile.gifmaker",
"com.kuaishou.nebula",
"com.baidu.searchbox",
"com.baidu.searchbox.lite",
"com.baidu.wenku"
)
);或者(Java 9+):
private static final List<String> HIGH_PRIORITY_PAG = List.of(
"com.smile.gifmaker",
"com.kuaishou.nebula",
"com.baidu.searchbox",
"com.baidu.searchbox.lite",
"com.baidu.wenku"
);这样定义可以防止运行时意外修改列表,提高代码健壮性。
动态包名列表 appList 由外部传入,可能会变化,因此我们定义为普通的 ArrayList:
private static List<String> appList = new ArrayList<>();getRandomPackageimport java.util.*;
import java.util.stream.Collectors;
public class PackageSelector {
private static List<String> appList = new ArrayList<>();
private static final List<String> HIGH_PRIORITY_PAG = List.of(
"com.smile.gifmaker",
"com.kuaishou.nebula",
"com.baidu.searchbox",
"com.baidu.searchbox.lite",
"com.baidu.wenku"
);
private static final Random random = new Random();
/
* 获取一个随机包名
* @return 随机选择的包名,如果所有列表都为空则返回null
*/
public static String getRandomPackage() {
// 如果appList为空,从HIGH_PRIORITY_PAG随机选择
if (appList.isEmpty()) {
return getRandomElement(HIGH_PRIORITY_PAG);
}
// 获取appList和HIGH_PRIORITY_PAG的交集
List<String> intersection = appList.stream()
.filter(HIGH_PRIORITY_PAG::contains)
.collect(Collectors.toList());
// 如果有交集,从交集中随机选择
if (!intersection.isEmpty()) {
return getRandomElement(intersection);
}
// 否则从appList中随机选择
return getRandomElement(appList);
}
/
* 从列表中随机选择一个元素
* @param list 源列表
* @return 随机选择的元素,如果列表为空则返回null
*/
private static String getRandomElement(List<String> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(random.nextInt(list.size()));
}
}getRandomPackage(): appList 是否为空,如果是,则从 HIGH_PRIORITY_PAG 随机选一个。appList 和 HIGH_PRIORITY_PAG 的交集: appList 随机选一个。getRandomElement(List<String> list): null,返回 null。为了验证方法的正确性,我们编写以下测试用例:
public static void main(String[] args) {
// 测试1: appList为空,从HIGH_PRIORITY_PAG随机选择
appList = new ArrayList<>();
System.out.println("Test 1: " + getRandomPackage()); // 输出 HIGH_PRIORITY_PAG 中的随机包名
// 测试2: appList包含HIGH_PRIORITY_PAG中的元素
appList = Arrays.asList("com.baidu.searchbox", "com.example.test", "com.other.app");
System.out.println("Test 2: " + getRandomPackage()); // 可能返回 "com.baidu.searchbox"
// 测试3: appList不包含HIGH_PRIORITY_PAG中的元素
appList = Arrays.asList("com.example.test1", "com.example.test2");
System.out.println("Test 3: " + getRandomPackage()); // 返回 "com.example.test1" 或 "com.example.test2"
// 测试4: appList和HIGH_PRIORITY_PAG都为空
appList = new ArrayList<>();
HIGH_PRIORITY_PAG = List.of(); // 假设HIGH_PRIORITY_PAG为空
System.out.println("Test 4: " + getRandomPackage()); // 返回 null
}如果 appList 可能被多线程修改,可以改为 CopyOnWriteArrayList:
private static final List<String> appList = new CopyOnWriteArrayList<>();如果列表较大,可以使用 ThreadLocalRandom 替代 Random:
private static String getRandomElement(List<String> list) {
if (list == null || list.isEmpty()) {
return null;
}
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
}如果需要某些包名被选中的概率更高,可以引入权重机制:
public static String getWeightedRandomPackage(Map<String, Integer> packageWeights) {
List<String> weightedList = new ArrayList<>();
for (Map.Entry<String, Integer> entry : packageWeights.entrySet()) {
for (int i = 0; i < entry.getValue(); i++) {
weightedList.add(entry.getKey());
}
}
return getRandomElement(weightedList);
}本文介绍了一种智能包名选择策略,核心要点包括:
Collections.unmodifiableList 或 List.of 定义高优先级列表。ArrayList 存储可变包名列表。NullPointerException。这种方法适用于广告SDK、渠道分发、AB测试等场景,能够灵活应对不同的包名选择需求。
完整代码已提供,欢迎在实际项目中应用! 🚀