2013-05-08 2 views
1

Я столкнулся с сложной проблемой при работе с приложениями Android - загрузкой класса из .zip или .dex в приложение. Я не могу решить проблему Classloader. Пожалуйста, помогите мне, спасибо. Я пытаюсь загрузить класс из zip, но класс (например, провайдер Android или что-то в этом роде) должен быть загружен при запуске программы. Итак, я должен оставить файл в своих программах, например, с пакетами com.example.androidprovider и файл TestProvider.java.Classloader, используемый в приложении для Android

package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
public static final String AUTHORY="com.lcz.tst"; 
     DBHelper dbHelp; 
     SQLiteDatabase sq; 
     @Override 
     public int delete(Uri uri, String selection, String[] selectionArgs) { 
       sq.delete(DBHelper.TABLE, selection, selectionArgs); 
       return 0; 
     } 
     ... 
     @Override 
     public boolean onCreate() { 
       dbHelp=new DBHelper(getContext(),null, null, 1); 
       sq=dbHelp.getWritableDatabase(); 
       Log.i("TestProvider", "text"); 
       return true; 
     } 
} 

В моем файле .zip, я упаковать класс с пакет com.example.androidprovider и именем класса TestProvider. (Два класса отличается, а второй класс является классом мне действительно нужно.)

package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
     public static final String AUTHORY="com.lcz.tst"; 
     DBHelper dbHelp; 
     SQLiteDatabase sq; 
     @Override 
     public int delete(Uri uri, String selection, String[] selectionArgs) { 
       sq.delete(DBHelper.TABLE, selection, selectionArgs); 
       return 0; 
     } 
     ... 
     @Override 
     public boolean onCreate() { 
       dbHelp=new DBHelper(getContext(),null, null, 1); 
       sq=dbHelp.getWritableDatabase(); 
       Log.i("Original Provider", "This is the original!!!"); 
       return true; 
     } 
} 

Теперь это мой код загрузчика.

public void loadDex(String strActivity){ 
     final File optimizedDexOutputPath = oriActivity.getDir("outdex", Context.MODE_PRIVATE); 
     // Initialize the class loader with the secondary dex file. 
     //dexInternalStoragePath.getAbsolutePath() is the path there the .zip is, 
     DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), 
       optimizedDexOutputPath.getAbsolutePath(), 
       libPath, 
       this.getClass().getClassLoader()); 
     Class<?> cls; 
     try { 
       cls = cl.loadClass("com.example.androidprovider.TestProvider"); 
       Object instant = cls.newInstance(); 
       Method method = cls.getDeclaredMethod("onCreate"); 
       method.invoke(instant); 
     }catch (Exception e) { 
       e.printStackTrace(); 
     } 

Я проверил LogCat, но журнал всегда показывает "TestProvider текст". Таким образом, это означает, что мой код загрузчика не удался. Я думаю, причина в том, что мое приложение инициализирует класс com.example.androidprovider.TestProvider (первый кусок кода), а загрузчик загружает другой класс с тем же пакетом и именем, поэтому второй класс не может быть успешно загружен.

Но мне действительно нужно загрузить второй класс. Могу ли я использовать некоторые способы запуска второго класса? Спасибо ...

ответ

0

Я действительно не понимаю, почему вы не загружаете оригинал в первую очередь, но в любом случае. Вы можете поместить в приложение прокси-класс, который делит вызов метода на ваш «оригинальный» класс. Но вам нужно использовать отражения!

package com.example.androidprovider; 
public class TestProviderProxy extends ContentProvider { 
    public boolean onCreate() { 
      // use reflections here -> GOOGLE IT 
      // something with clazz = context.getClassloader().loadClass(
      // "com.example.androidprovider.TestProvider"); 
      // method = clazz.getMethod("onCreate") 
      return method.invoke(); 
    } 
} 

package com.example.androidprovider; 
public class TestProvider extends ContentProvider { 
    public boolean onCreate() { 
      dbHelp=new DBHelper(getContext(),null, null, 1); 
      sq=dbHelp.getWritableDatabase(); 
      Log.i("Original Provider", "This is the original!!!"); 
      return true; 
    } 
} 
+0

Спасибо. Возможно, это может работать хорошо. В моем примере первый TestProviderProxy должен измениться как можно меньше. Это всего лишь кусок тестового кода, на самом деле, возможно, я не могу получить исходный код первого TestProviderProxy. Но он должен быть инициализирован из-за файла AndroidMenifest.xml в приложении Android Appliciton. Поэтому я должен написать альтернативный TestProviderProxy (второй), чтобы загрузить фактический TestProviderProxy (первый). Я не думал переписывать свой альтернативный TestProviderProxy, я попробую. Большое спасибо! –

+0

Кстати, я знаю, что отражение действительно мощное. так, могу ли я иметь некоторые способы охватить первый класс вторым классом во время выполнения? Я думаю, возможно, это может сработать, изменив некоторые данные системного уровня с отражением, но я не знал, какие данные следует изменить. Благодарю. –

+0

Я все еще не уверен, чего вы пытаетесь достичь ... но я надеюсь, что это вам помогло. Да отражения «мощные», но сама система работает на собственном коде, а ваше приложение работает в SandBox. Вы не можете просто изменить «некоторые данные», чтобы сделать всю работу. – cwin

1

уборщик способ сделать это было бы модифицировать загрузчик классов базового контексте путем переопределения attachBaseContext() в своем классе приложений.

protected void attachBaseContext(Context base) 
{ 
    Log.i(loggerName, "Attaching base context"); 
    super.attachBaseContext(base); 

    // Modify base.getClassLoader() via reflection. 
    // Load classes as normal without having to tinker around with loadClass etc. 

} 
Смежные вопросы