Android 與 JDK 下查找包下的類

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章