Android 與 JDK 下查找包下的類
本文的標題可以看出,Android與JDK查找包下的類並列標題,主要原因是最近在寫的一個項目,相同的代碼可能在不同的平臺執行。而在JDK環境測試OK的代碼到Android設備上就不正常了,於是查找了些資料。具體原因因爲ClassLoader.getResource(name)實現不同。最終實現如下,不同平臺進行了封裝,只需要調用以下代碼即可:
List<String> classes = ClassScannerFactory.getScanner().scannClassess("cn.canney");
先看下項目結構
下面上代碼
/**
* 類掃描器
* @author Canney Chen
*
*/
public abstract class ClassScanner {
/**
* 掃描包下的類
* @param pck
* @return
* @throws Exception
*/
public List<String> scannClassess(String pck) throws Exception{
if(!checkPackage(pck)){
throw new Exception("package invalid:" + pck);
}
return onScannClasses(pck);
}
private boolean checkPackage(String pck){
if(pck == null || "".equals(pck)){
return false;
}else if(pck.startsWith(".") || pck.endsWith(".")){
return false;
}
return true;
}
protected abstract List<String> onScannClasses(String pck) throws Exception;
}
package cn.canney.util;
public class ClassScannerFactory {
public static ClassScanner getScanner(){
if(isOnAndroid()){
return new AndroidClassScanner();
}else{
return new CommonClassScanner();
}
}
public static boolean isOnAndroid(){
return System.getProperty("java.runtime.name").contains("Android");
}
}
/**
* {@link Class#getResource(String)}能正常加載資源的類掃描器實現
* @author Canney Chen
*
*/
public class CommonClassScanner extends ClassScanner {
@Override
public List<String> onScannClasses(String pck) throws Exception {
List<String> classes = new ArrayList<String>();
scanClasses(pck, classes);
return classes;
}
private void scanClasses(String pck, List<String> classes) throws URISyntaxException{
String path = "/" + pck.replace(".", "/");
URL url = ClassScanner.class.getResource(path);
File pckDir = new File(url.toURI());
File[] fs = pckDir.listFiles();
if(fs == null){
return ;
}
for (int i = 0; i < fs.length; i++) {
File f = fs[i];
String fillPck = new StringBuffer(pck).append(".").append(f.getName()).toString();
if(f.isFile()){
String className = fillPck.replace(".class", "");
classes.add(className);
}else{
scanClasses(fillPck, classes);
}
}
}
}
/**
* Android 類掃描器實現
* @author Canney Chen
*
*/
public class AndroidClassScanner extends ClassScanner {
@Override
protected List<String> onScannClasses(String pck) throws Exception {
DexFile df = new DexFile(getPackageCodePath());
List<String> classes = new ArrayList<String>();
Enumeration<String> en = df.entries();
while(en.hasMoreElements()){
String e = en.nextElement();
if(e.startsWith(pck)){
classes.add(e);
}
}
return classes;
}
/**
* 此處考慮到強引用關係並未使用{@link Context#getPackageCodePath()}
* @return
*/
private String getPackageCodePath(){
URL url = ClassScanner.class.getResource("scan");
String path = url.getPath();
return path.substring(0, path.indexOf("!")).replace("file:", "");
}
}
本文參考以下資料
主要對查找資源方法ClassLoader.getResource(name)進行了說明
https://github.com/hunterhacker/jdom/wiki/JDOM2—Android-Issue—getSystemResource
Android平臺實現包下類掃描的一些問答
http://stackoverflow.com/questions/15446036/find-all-classes-in-a-package-in-android