1

我在处理 Android 应用程序时遇到了一个棘手的问题——从应用程序中的 .zip 或 .dex 加载类。我无法处理这个Classloader问题。请帮助我,谢谢。我正在尝试从 zip 加载一个类,但是在程序启动时需要加载该类(例如 Android 提供程序或类似的东西)。所以,我必须在我的程序中留下一个文件,例如,包含包com.example.androidprovider和文件 TestProvider.java。

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 text"。所以,这意味着我的加载器代码失败了。我认为原因是,我的应用程序初始化了一个com.example.androidprovider.TestProvider(第一段代码)类,并且加载器加载了具有相同包和名称的不同类,因此无法成功加载第二个类。

但我真的需要加载第二节课。我可以用一些方法开始第二节课吗?谢谢...

4

2 回答 2

1

一种更简洁的方法是通过覆盖 Application 类中的 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.

}
于 2014-01-26T10:59:08.210 回答
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;
  }
}
于 2013-05-08T13:25:33.553 回答