2013-08-22 2 views
3

Я использовал Reflections Библиотека для поиска всех подклассов данного класса в Java раньше.Найти все подклассы данного класса (Android)

Это фрагмент кода, который я использую в простой Java проекта в:

Reflections reflections = new Reflections(PACKAGE_NAME); 

    Set<Class<? extends SuperClass>> subTypes = 
      reflections.getSubTypesOf(SuperClass.class); 

    for (Class<? extends SuperClass> subType : subTypes) { 

     log("Subclass = " + subType.getSimpleName()); 
    } 

Когда я запускаю тот же код в андроида проекта, «подтип» Список возвращает пустой.

Может ли кто-нибудь помочь мне получить эту работу на Android?

EDIT баночки я добавить для всей вещи на труд:

  • отражений-0.9.9-RC1-uberjar.jar
  • Javassist-3.12.1.GA.jar
  • guava-14.0.1.jar
+0

Вы смотрели на [это] (http://stackoverflow.com/questions/ 5679254/все-супер-классы в своем-классе)? – t0mm13b

+0

@ t0mm13b. Это о суперклассах, а не подклассах. –

+0

@RohitJain, то почему код OP ссылается на 'SuperClass.Class'? – t0mm13b

ответ

0

Это может не работать из-за процесса компиляции, используемого в Android. Исходный код преобразуется в .class-файлы с помощью компилятора Java. Следующий шаг превращает файлы .class в файлы Android .dex (байт-код Dalvik), и они вряд ли будут хранить все метаданные.

http://developer.android.com/tools/building/index.html

+0

Да, я так и думал ... Как вы думаете, есть способ заставить его работать в любом случае ? Может быть, написать какой-то крючок, который будет работать во время компиляции? – Ivelius

+0

Извините, нет гуру компилятора.Вы можете проверить что-то вроде этого http://android-developers.blogspot.co.il/2011/07/custom-class-loading-in-dalvik.html – mach

+0

Интересное сообщение. Спасибо. Я с нетерпением решение. – Ivelius

0

Существует официальный API для работы с файлами тны. См. here. В принципе, заданный путь файла .dex, вы можете перечислить все файлы внутри него. Чтобы получить URL в classes.dex, вы можете использовать

Thread.currentThread().getContextClassLoader().getResource("classes.dex") 

(возможно, потребуется вырезать задний "!/classes.dex", не может проверить это прямо сейчас). Затем вы можете перебирать содержимое classes.dex и пытаться загрузить все классы, которые вы находите таким образом. (Class.forName) и, наконец, проверьте все необходимые свойства класса. Имейте в виду, однако, что classes.dex содержит все классов, а «все» могут быть «довольно много». Также есть другие проблемы с производительностью, которые нужно помнить при работе с файлами .dex. Вы должны, однако, быть в порядке, если вы не пытаетесь что-то бесполезно неэффективно. Тем более, что Reflections выполняет свою магию подобным образом, насколько я могу себе представить.

1

может быть, вы можете попробовать это:

public abstract class ClassScanner { 

    private static final String TAG = "ClassScanner"; 
    private Context mContext; 

    public ClassScanner(Context context) { 
     mContext = context; 
    } 

    public Context getContext() { 
     return mContext; 
    } 

    void scan() throws IOException, ClassNotFoundException, NoSuchMethodException { 
     long timeBegin = System.currentTimeMillis(); 

     PathClassLoader classLoader = (PathClassLoader) getContext().getClassLoader(); 
     //PathClassLoader classLoader = (PathClassLoader) Thread.currentThread().getContextClassLoader();//This also works good 
     DexFile dexFile = new DexFile(getContext().getPackageCodePath()); 
     Enumeration<String> classNames = dexFile.entries(); 
     while (classNames.hasMoreElements()) { 
      String className = classNames.nextElement(); 
      if (isTargetClassName(className)) { 
       //Class<?> aClass = Class.forName(className);//java.lang.ExceptionInInitializerError 
       //Class<?> aClass = Class.forName(className, false, classLoader);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1 
       Class<?> aClass = classLoader.loadClass(className);//tested on 魅蓝Note(M463C)_Android4.4.4 and Mi2s_Android5.1.1 
       if (isTargetClass(aClass)) { 
        onScanResult(aClass); 
       } 
      } 
     } 

     long timeEnd = System.currentTimeMillis(); 
     long timeElapsed = timeEnd - timeBegin; 
     Log.d(TAG, "scan() cost " + timeElapsed + "ms"); 
    } 

    protected abstract boolean isTargetClassName(String className); 

    protected abstract boolean isTargetClass(Class clazz); 

    protected abstract void onScanResult(Class clazz); 
} 

и это пример того, как использовать:

new ClassScanner(context) { 

    @Override 
    protected boolean isTargetClassName(String className) { 
     return className.startsWith(getContext().getPackageName())//I want classes under my package 
       && !className.contains("$");//I don't need none-static inner classes 
    } 

    @Override 
    protected boolean isTargetClass(Class clazz) { 
     return AbsFactory.class.isAssignableFrom(clazz)//I want subclasses of AbsFactory 
       && !Modifier.isAbstract(clazz.getModifiers());//I don't want abstract classes 
    } 

    @Override 
    protected void onScanResult(Class clazz) { 
     Constructor constructor = null; 
     try { 
      constructor = clazz.getDeclaredConstructor(); 
      constructor.setAccessible(true); 
      constructor.newInstance(); 
     } catch (NoSuchMethodException e) { 
      e.printStackTrace(); 
     } catch (InstantiationException e) { 
      e.printStackTrace(); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } catch (InvocationTargetException e) { 
      e.printStackTrace(); 
     } 
    } 

}.scan(); 
Смежные вопросы