5

私はJ2SEおよびAndroidプロジェクトで使用するプラットフォームに依存しないライブラリを作成しました。このライブラリ内には、Versionクラスがあり、マニフェストからそのバージョンの詳細をロードします。 PC上でこれはうまくいく、私はNullPointerExceptionを取得しているアンドロイドで、私は理由を理解することはできません。Class.getResource(className)私にNullPointerExceptionを与える

これは私のクラスである:

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; 
    } 
} 

(これらは、PC上でデバッグするためのもので、System.err.println()ラインを言い訳してください)。

これはPCではうまく動作しますが、Androidでは動作しないのはなぜですか?

のフルスタックトレース:

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 

更新:両方のPCとAndroid上className = Version.classgetSimpleName()の代わりにgetName()を使用すると、PCで壊れても、Androidでは動作しません。

+0

スタックトレース?... – Matt

+0

彼はそれがスローされたコード内の行をコメントしました。 – WarrenFaith

+0

ちょうどの場合にスタックトレースが追加されました。それはあまり有用ではありません:/ – Logan

答えて

1

私は100%確実ではありませんが、実際のJVMと同じようにAndroidではこのメカニズムが機能しているとは思わない(dalvikは基本的にJVMではないため)。私はと思って(と私は間違っているかもしれません)、パッケージAPKでは、JARはもはや存在しないため、おそらくリソースへのパスは間違っています。 JARのクラスは、dexファイル形式とadded to the classes.dex fileに変換されます。したがって、クラスパスに存在しないため、foo.bar.classのようなリソースを解決することはできません。

バージョン情報をテキスト(または他のリソース)ファイルに入れてJARに追加して読み込みます。リソースファイルは適切に追加する必要があり、メカニズムでそれを読むことができるはずです。

+0

私はAPKの部分について完全に忘れていました。ライブラリがjarファイルに入っているので、APK自体の中にパッケージ化されていて、それでもすべてが機能すると思っていました。 – Logan

+0

私はいくつかの説明と、プラットフォームに依存しない方法でそれを克服する方法を追加しました。 – Stephan

+0

私は 'version'ファイルを'/res'に入れて、 'Property'クラスを使ってそれを読み込みました。これはAndroidと標準Javaの両方で完璧に動作します。 – Logan

2

メソッド呼び出しclazz.getResource(className)classNameで指定されたリソースが見つからないことを意味しているnullを返しているので、あなたはNullPointerExceptionを得ています。
リソースファイルをフォルダに入れ、リソースフォルダとして設定します。詳細については、this answer on SOを確認してください。
また、this SO answerには、再送信フォルダに関する情報が表示されます。

+0

私のリソースはjarファイル内のクラスです。 :/ – Logan

+0

jarファイルがクラスパスにある限り問題はありません。 jarファイルをapkファイルと共にエクスポートしていますか? –

+1

私はそうしていると思います。そうでなければ、ライブラリの実際の肉は働いていません(現状です)。 – Logan

0

バージョン情報をマニフェストファイルに保存し、実行時にそれを抽出すると思います。もしそうなら、Androidへようこそ:-)

あなたが直面している問題ではなく、いくつかのオプションがあります。

Context
  • 使用PackageManager

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

    その後PackageInfoとあなたがpackageNameversionCodeversionNameを持っているが...これらはAndroidManifest.xmlで定義されています。

  • Storeはresourcesであなたのバージョン情報などStringIntegerは...あなたもContextがリソースを取得する必要があります。

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

私はそれらが優れていると思います。

+0

これはAndroid固有のものです。私はプラットフォームの独立性が必要です。しかし、本質的にこれは私がしたいことです。 – Logan

関連する問題