JMonkey Android自定义类加载

时间:2014-07-28 09:30:52

标签: android dynamic classloader dex jmonkeyengine

我已经完成了超过65 000种方法的JMonkey个应用。我想在android上运行它。所以,我使用multi dex选项来构建apk。然后我动态加载第二个.dex文件。

我将第二个.dex文件存储在一个jar中,位于apk的资产目录中。

这是我的Android主要活动代码:

public class MainActivityStart extends Activity {

   private static final String SECONDARY_DEX_NAME = "classes2.jar";

/**
 * Buffer size for file copying. While 8kb is used in this sample, you may
 * want to tweak it based on actual size of the secondary dex file involved.
 */
private static final int BUF_SIZE = 8 * 1024;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    loadSecondaryDex();

    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
    startActivity(intent);

}

private void loadSecondaryDex() {
    // Before the secondary dex file can be processed by the DexClassLoader,
    // it has to be first copied from asset resource to a storage location.
    final File dexInternalStoragePath = new File(getDir("dex",
            Context.MODE_PRIVATE), SECONDARY_DEX_NAME);

    prepareDex(dexInternalStoragePath);

    final File dexOutputDir = getDir("outdex", 0);

    DexClassLoader cl = new DexClassLoader(
            dexInternalStoragePath.getAbsolutePath(),
            dexOutputDir.getAbsolutePath(), null, getClassLoader()) {

        @Override
        public Class<?> loadClass(final String className)
                throws ClassNotFoundException {
            return super.loadClass(className);
        }
    };

}

// File I/O code to copy the secondary dex file from asset resource to
// internal storage.
private void prepareDex(final File dexInternalStoragePath) {
    BufferedInputStream bis = null;
    OutputStream dexWriter = null;

    try {
        bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME));
        dexWriter = new BufferedOutputStream(new FileOutputStream(
                dexInternalStoragePath));
        final byte[] buf = new byte[BUF_SIZE];
        int len;
        while ((len = bis.read(buf, 0, BUF_SIZE)) > 0) {
            dexWriter.write(buf, 0, len);
        }

        dexWriter.close();
        bis.close();
        // return true;
    } catch (final IOException e) {
        if (dexWriter != null) {
            try {
                dexWriter.close();
            } catch (final IOException ioe) {
                ioe.printStackTrace();
            }
        }
        if (bis != null) {
            try {
                bis.close();
            } catch (final IOException ioe) {
                ioe.printStackTrace();
            }
        }
        // return false;
    }
}

}

如您所见,当动态类加载完成后,我切换到Jmonkey Activity。这个扩展了AndroidHarness类适用于Android的JME应用程序。

以下是代码:

public class MainActivity extends AndroidHarness {

public MainActivity() {

    // Set the application class to run
    appClass = "mygame.Main";

    // Try ConfigType.FASTEST; or ConfigType.LEGACY if you have problems
    eglConfigType = ConfigType.LEGACY;

    // Exit Dialog title & message
    exitDialogTitle = "Quit game?";
    exitDialogMessage = "Do you really want to quit the game?";

    // Choose screen orientation
    screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

    // Invert the MouseEvents X (default = true)
    mouseEventsInvertX = true;

    // Invert the MouseEvents Y (default = true)
    mouseEventsInvertY = true;
  }
}

运行这个给我一个很好的例外:

  

07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):SEVERE类mygame.Main init失败   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):java.lang.ClassNotFoundException:mygame.Main   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.Class.classForName(Native Method)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.Class.forName(Class.java:251)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.Class.forName(Class.java:216)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at com.jme3.app.AndroidHarness.onCreate(AndroidHarness.java:223)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.Activity.performCreate(Activity.java:5231)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.ActivityThread.access $ 800(ActivityThread.java:135)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1196)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.os.Handler.dispatchMessage(Handler.java:102)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.os.Looper.loop(Looper.java:136)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):在android.app.ActivityThread.main(ActivityThread.java:5001)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.reflect.Method.invokeNative(Native Method)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.reflect.Method.invoke(Method.java:515)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:785)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at dalvik.system.NativeStart.main(Native Method)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):引起:java.lang.NoClassDefFoundError:mygame / Main   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):... 18更多   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):引起:java.lang.ClassNotFoundException:找不到类&#34; mygame.Main&#34; on path:DexPathList [[zip file&#34; /data/app/com.example.j4a-1.apk"],nativeLibraryDirectories = [/ data / app-lib / com.example.j4a-1,/ vendor / lib,/ system / lib]]   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.ClassLoader.loadClass(ClassLoader.java:497)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):at java.lang.ClassLoader.loadClass(ClassLoader.java:457)   07-28 10:59:21.645:E / com.jme3.app.AndroidHarness(3788):... 18更多

所以,找不到主要课程......你们有没有想过要做的伎俩?

另外一个问题: 我无法直接在扩展AndroidHarness的MainActivity类中访问Activity类提供的方法,例如getDir(); getAssets();或者更重要的是,getContext(); 它将永远返回NPE ......

如果我能这样做,我将能够在这个类中进行动态加载并通过反射调用mygame.Main类,这可能很棒。所以,如果你们有解决方案......先谢谢你们!

1 个答案:

答案 0 :(得分:0)

您的问题似乎与ClassLoader有关。

当您调用Class.forName(MyGame)时,VM会尝试从调用ClassLoader(与包含调用Class.forName的类关联的ClassLoader)中查找该类。 根据你的帖子,我认为你的类还没有被加载,或者已被另一个ClassLoader加载。

在调用Class.forName之前,必须确保已经加载了要查找的类,并且已经加载了与加载调用类的类或其父类之一相同的ClassLoader。