5

Ho creato una libreria indipendente dalla piattaforma che desidero utilizzare su un progetto J2SE e Android. All'interno di questa libreria ho una classe Version che carica i dettagli della sua versione dal manifest. Su PC funziona bene, su Android sto ottenendo uno NullPointerException e non riesco a capire perché.Class.getResource (className) assegnandomi NullPointerException

Questa è la mia classe:

public class Version { 

    private static int APPCODE = 12354; 
    private static int MAJOR; 
    private static int MINOR; 
    private static char RELEASE; 
    private static int BUILD; 
    private static int PROTOCOL; 

    static { 
     try { 
      Class clazz = Version.class; 
      String className = clazz.getSimpleName() + ".class"; 
      String classPath = clazz.getResource(className).toString(); //NullPointerException 
      if (classPath.startsWith("jar")) { 
       String manifestPath = classPath.substring(0, 
         classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; 
       Manifest manifest = new Manifest(new URL(manifestPath).openStream()); 
       Attributes attr = manifest.getMainAttributes(); 
       //APPCODE = Integer.parseInt(attr.getValue("APPCODE")); 
       MAJOR = Integer.parseInt(attr.getValue("MAJOR")); 
       MINOR = Integer.parseInt(attr.getValue("MINOR")); 
       RELEASE = attr.getValue("RELEASE").charAt(0); 
       BUILD = Integer.parseInt(attr.getValue("BUILD")); 
       PROTOCOL = Integer.parseInt(attr.getValue("PROTOCOL")); 
      } else { 
       System.err.println("Couldn't find manifest, reverting to test mode"); 
       MAJOR = 0; 
       MINOR = 0; 
       RELEASE = 'n'; 
       BUILD = 0; 
       //APPCODE = 12354; 
      } 
     } catch (IOException e) { 
      System.err.println("Failed to load manifest file. " + e); 
      MAJOR = 0; 
      MINOR = 0; 
      RELEASE = '0'; 
      BUILD = 0; 
      //APPCODE = 12354; 
      PROTOCOL = 0; 
     } catch (NumberFormatException e) { 
      System.err.println("Failed to load manifest file. " + e); 
      MAJOR = 0; 
      MINOR = 0; 
      RELEASE = '0'; 
      BUILD = 0; 
      //APPCODE = 12354; 
      PROTOCOL = 0; 
     } 
    } 

    public static int getProtocol() { 
     return PROTOCOL; 
    } 

    public static int getAppCode() { 
     return APPCODE; 
    } 

    public static int getBuildNumber() { 
     return BUILD; 
    } 

    public static int getMajor() { 
     return MAJOR; 
    } 

    public static int getMinor() { 
     return MINOR; 
    } 

    public static char getRelease() { 
     return RELEASE; 
    } 
} 

(Chiedo scusa per le System.err.println() linee, quelli sono per il debug su PC).

Perché questo funziona correttamente su PC ma non su Android?

completa analisi dello stack:

03-12 22:13:11.687: E/AndroidRuntime(11780): FATAL EXCEPTION: main 
03-12 22:13:11.687: E/AndroidRuntime(11780): java.lang.ExceptionInInitializerError 
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.logandam.wififileshare.android.MainActivity.onCreate(MainActivity.java:24) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.Activity.performCreate(Activity.java:4465) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1052) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1932) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1993) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.access$600(ActivityThread.java:127) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1159) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.os.Handler.dispatchMessage(Handler.java:99) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.os.Looper.loop(Looper.java:137) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at android.app.ActivityThread.main(ActivityThread.java:4507) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at java.lang.reflect.Method.invokeNative(Native Method) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at java.lang.reflect.Method.invoke(Method.java:511) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557) 
03-12 22:13:11.687: E/AndroidRuntime(11780): at dalvik.system.NativeStart.main(Native Method) 
03-12 22:13:11.687: E/AndroidRuntime(11780): Caused by: java.lang.NullPointerException 
03-12 22:13:11.687: E/AndroidRuntime(11780): at com.logandam.wififileshare.net.Version.<clinit>(Version.java:30) 
03-12 22:13:11.687: E/AndroidRuntime(11780): ... 15 more 

Aggiornamento: className = Version.class su entrambi i PC e Android. L'utilizzo di getName() anziché di getSimpleName() interrompe su PC e continua a non funzionare su Android.

+0

Traccia stack? ... – Matt

+0

ha commentato la riga nel codice in cui è stata generata ... – WarrenFaith

+0

Aggiunta traccia dello stack per ogni evenienza. Non è molto utile:/ – Logan

risposta

1

Non sono sicuro al 100%, ma non penso che questo meccanismo funzioni con Android come in una JVM reale (dalValvik non è essenzialmente una JVM). I penso (e potrei sbagliarmi qui), che nell'APK impacchettato, il JAR non esiste più e quindi il tuo percorso verso la risorsa probabilmente è sbagliato. Le classi del tuo JAR vengono convertite nel formato file dex e added to the classes.dex file. Pertanto non è possibile risolvere una risorsa come foo.bar.class perché non esiste nel classpath.

Provare a inserire le informazioni sulla versione in un file di testo (o altra risorsa) e aggiungerle nel JAR e leggerle. Il file di risorse dovrebbe essere aggiunto correttamente e dovresti essere in grado di leggerlo con il meccanismo.

+0

Mi ero completamente dimenticato della parte APK. Ho appena capito che dato che la libreria si trova in un file jar, sarebbe stata inserita all'interno dell'APK stesso e tutto funzionerebbe ancora. – Logan

+0

Ho aggiunto qualche spiegazione in più e un'idea su come superarla in modo indipendente dalla piattaforma. – Stephan

+0

Ho finito per inserire un file 'version' in'/res' e poi usare la classe 'Property' per leggerlo in modo ordinato, che funziona perfettamente sia su Android che su Java standard. – Logan

2

Hai trovato NullPointerException perché la chiamata al metodo clazz.getResource(className) sta tornando null il che significa che la risorsa specificata da className non può essere trovato.
Inserisci il tuo file di risorse in una cartella e impostalo come cartella delle risorse. Controllare this answer on SO per ulteriori informazioni.
È inoltre possibile controllare this SO answer per detials sulle cartelle di risorse.

+0

Tranne la mia risorsa è una classe in un file jar. :/ – Logan

+0

Non ci saranno problemi finché il file jar si trova nel classpath. Sei sicuro di voler esportare il file jar insieme al tuo file apk? –

+1

Sto assumendo così, altrimenti la carne reale della libreria non funzionerebbe (che attualmente è). – Logan

0

Penso che si voglia mantenere le informazioni sulla versione nel file manifest ed estrarlo in runtime. Se è così, benvenuto su Android :-)

Hai diverse opzioni migliori piuttosto che quella con problemi che stai affrontando.

  • Usa PackageManager con un Context:

    PackageInfo pi = context.getPackageManager().getPackageInfo(
         context.getPackageName(), 0); 
    

    Poi, con PackageInfo voi hanno packageName, versionCode, versionName ... Quelli sono definiti in AndroidManifest.xml.

  • possibile memorizzare le informazioni di versione nel resources, come ad esempio String, Integer ... è necessario anche un Context di reperire le risorse:

    String appDescription = context.getString(R.string.app_description); 
    int majorBuild = context.getResources().getInteger(R.integer.major_build); 
    // ... 
    

Credo che quelle sono meglio.

+0

Questo è specifico per Android. Ho bisogno di indipendenza dalla piattaforma. Ma in sostanza questo è quello che voglio fare. – Logan

Problemi correlati