Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/204.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android dalvik.system.PathClassLoader未加载多个JAR_Android_Jar_Classloader - Fatal编程技术网

Android dalvik.system.PathClassLoader未加载多个JAR

Android dalvik.system.PathClassLoader未加载多个JAR,android,jar,classloader,Android,Jar,Classloader,我试图加载一组JAR文件,这些文件一起组成一个API。出于某种原因,我只能加载不依赖于其他JAR中定义的类。我开始怀疑Android类加载器根本无法处理从一个JAR文件到另一个JAR文件的接口实现。出于这个原因,我还将这些类解压到一个公共目录中,但是这也不起作用 请参阅以下代码。对于任何异常情况,我深表歉意,但我已尝试确保它在粘贴到名为MyProj的ADT项目中时能够直接编译 import java.io.File; import java.io.FileOutputStream; import

我试图加载一组JAR文件,这些文件一起组成一个API。出于某种原因,我只能加载不依赖于其他JAR中定义的类。我开始怀疑Android类加载器根本无法处理从一个JAR文件到另一个JAR文件的接口实现。出于这个原因,我还将这些类解压到一个公共目录中,但是这也不起作用

请参阅以下代码。对于任何异常情况,我深表歉意,但我已尝试确保它在粘贴到名为MyProj的ADT项目中时能够直接编译

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import java.lang.reflect.Field;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;

import dalvik.system.PathClassLoader;
import android.content.Context;

    // IPluginSource simply defines the method here at the top.
public class AndroidPluginSource implements IPluginSource 
{
    @Override
    public void doSearching(ArrayList<ClassLoader> classLoaders, ArrayList<String> classNames) 
    {
        String jarPaths = "";

            // For each of the raw resources, JARs compiled into the 'res/raw' dir...
        for (Field str : R.raw.class.getFields())
        {
            String resName = str.getName();

            Logger.log(Level.FINE, "Resource: " + str);
            try 
            {
                                    // Copy the JAR file to the local FS.
                InputStream is = MyProj.self.getResources().openRawResource(str.getInt(this));
                OutputStream os = MyProj.self.openFileOutput(resName + ".jar", Context.MODE_PRIVATE);

                copyData(is, os);

                is.close();
                os.close();

                                    // Get JAR location.
                String jarLoc = MyProj.self.getFilesDir() + File.separator + resName + ".jar";
                                // First attempt is just single classloaders, so we aren't suprised this won't work.
                classLoaders.add(new PathClassLoader(jarLoc, MyProj.self.getClassLoader()));
                //Logger.log(Level.FINE, "  LOC: " + jarLoc);

                                    // Keep running list of JAR paths, will that work?
                if (jarPaths.length() > 0) jarPaths += File.pathSeparator;
                jarPaths += jarLoc;

                                    // We have to go through the JARs to get class names...
                JarFile jar = new JarFile(jarLoc);
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements())
                {
                    JarEntry entry = entries.nextElement();
                    String entryName = entry.getName();

                    if (entryName.endsWith(".class"))
                    {
                        classNames.add(toClassName(entryName));
                        Logger.log(Level.FINE, "    ENT: " + entryName);

                                    // ...while we're here lets get the class out as a file.
                        String classLoc = MyProj.self.getFilesDir() + File.separator + entryName;
                        Logger.log(Level.FINER, "    CLS: " + classLoc);
                        File classFile = new File(classLoc);
                        classFile.delete();
                        classFile.getParentFile().mkdirs();

                        InputStream jis = jar.getInputStream(entry);
                        //OutputStream jos = MyProj.self.openFileOutput(classLoc, Context.MODE_PRIVATE);
                        OutputStream jos = new FileOutputStream(classFile);

                        copyData(jis, jos);

                        jos.close();
                        jis.close();
                    }
                }
            } 
            catch (Exception ex)
            {
                Logger.log(Level.SEVERE, "Failed plugin search", ex);
            }
        }

        File f = MyProj.self.getFilesDir();
        recursiveList(f, 0);

        // So we have a class loader loading classes...
        PathClassLoader cl = new PathClassLoader(VermilionAndroid.self.getFilesDir().getAbsolutePath(), ClassLoader.getSystemClassLoader());
        classLoaders.add(cl);

        // A JAR loader loading all the JARs...
        PathClassLoader jl = new PathClassLoader(jarPaths, ClassLoader.getSystemClassLoader());
        classLoaders.add(jl);

        // And if edited as below we also have a DexLoader and URLClassLoader.
    }

            // This is just so we can check the classes were all unpacked together.
    private void recursiveList(File f, int indent)
    {
        StringBuilder sb = new StringBuilder();
        for (int x = 0; x < indent; x++) sb.append(" ");
        sb.append(f.toString());

        Logger.log(Level.INFO, sb.toString());

        File[] subs = f.listFiles();
        if (subs != null)
        {
            for (File g : subs) recursiveList(g, indent+4);
        }
    }

            // Android helper copy file function.
    private void copyData(InputStream is, OutputStream os)
    {
        try
        {
            int bytesRead = 1;
            byte[] buffer = new byte[4096];
            while (bytesRead > 0)
            {
                bytesRead = is.read(buffer);
                if (bytesRead > 0) os.write(buffer, 0, bytesRead);
            }
        }
        catch (Exception ex) {}
    }

        // Goes from a file name or JAR entry name to a full classname.
    private static String toClassName(String fileName)
    {
        // The JAR entry always has the directories as "/".
        String className = fileName.replace(".class", "").replace(File.separatorChar, '.').replace('/', '.');
        return className;
    }   
}
…这将导致一个新的异常-UnsupportdOperationException:无法加载此类类文件

以及:

也没有正常工作,但感谢您的建议Peter Knego

我应该澄清,在JAR文件中,我有:

JAR1:
    public interface IThing
    public class ThingA implements IThing

JAR2:
    public class ThingB implements IThing

我不完全确定您想做什么,但我怀疑Java语言对类装入器的定义不支持您想要的

类装入器按层次结构排列。如果您向类加载器CL1请求类Foo的副本,它将询问其父级是否知道Foo是什么。这将沿着链向上到达引导加载程序,当事情失败时,它将返回,直到最终CL1有机会找到一个副本。(它不必以这种方式工作,而且有一个测试用例故意将它“弄错”,但它几乎总是这样做的。)

假设CL1定义了Foo。Foo实现了IBar,因此在准备该类时,VM将要求CL1查找IBar。通常的搜索已经完成

如果在CL2中定义了IBar,并且CL2不是CL1的父级,那么CL1中的任何内容都无法看到IBar

因此,如果要为各种jar文件创建一组“对等”类装入器,就不能在它们之间直接引用类

这不是Android独有的


如果您创建一个类加载器并将整个JAR集放入路径中,您可以根据需要进行混合和匹配。

这个问题没有解决方案,到目前为止,我已经解决了。

请看一看:抱歉,您完全错了。这正是该项目目前在PC上运行的方式…再次抱歉,我重读了你的文章,你在最后一段中所说的正是我试图解决的问题——用上面列出的四种不同的方法……我还尝试将类加载器链接在一起作为孩子和家长。上面列出的最后一次尝试的失败是什么?(设备没有/tmp目录,所以我想确保它不会因此而失败。)失败类似于“您无法加载那种类型的类文件”。我知道二进制不兼容必须在某个地方发生!:-)
    URLClassLoader ul = null;
    try 
    {
        URL[] contents = new URL[jarURLs.size()];
        ul = new URLClassLoader(jarURLs.toArray(contents), ClassLoader.getSystemClassLoader());
    } 
    catch (Exception e) {} 
    classLoaders.add(ul);        
    DexClassLoader dl = new DexClassLoader(jarPaths, "/tmp", null, getClass().getClassLoader());
    classLoaders.add(dl);
JAR1:
    public interface IThing
    public class ThingA implements IThing

JAR2:
    public class ThingB implements IThing