5

J2SE ve Android projelerinde kullanmak istediğim platform bağımsız bir kitaplık hazırladım. Bu kitaplık içinde, sürüm ayrıntılarını bildiriden yükleyen bir Version sınıfına sahibim. PC'de bu iyi çalışıyor, Android'de bir NullPointerException alıyorum ve nedenini anlayamıyorum. Class.getResource (className) bana veren NullPointerException

Bu

benim sınıftır:

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

(System.err.println() satırları Lütfen bağışlayın, bu PC'de ayıklama içindir).

Bu neden bilgisayarda iyi çalışıyor, ancak Android'de çalışmıyor?

Tam yığın takibi:

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 

Güncelleme: hem PC hem Android'de className = Version.class. PC'de getSimpleName() yerine getName()'u kullanmak ve hala Android'de çalışmaz. clazz.getResource(className)className tarafından belirtilen kaynağı anlamına gelen null dönüyor yöntem çağrısı bulunamadığı çünkü

+0

Yığın izleme? ... – Matt

+0

o satır atılan satırda yorumladı ... – WarrenFaith

+0

Sadece durumda durumda yığın izleme ekledi. Çok işe yaramıyor:/ – Logan

cevap

1

% 100 emin değilim ama bu mekanizmanın gerçek bir JVM'de olduğu gibi Android altında çalıştığını sanmıyorum (çünkü dalvik esasen bir JVM değil). Ben (ve burada yanlış olabilir) düşünün, paketlenmiş APK'da, JAR artık yok ve bu nedenle kaynak yolunuz muhtemelen yanlıştır. JAR'ınızın sınıfları dex dosya formatına ve added to the classes.dex file'a dönüştürülür. Bu nedenle, sınıf yolunda bulunmadığı için foo.bar.class gibi bir kaynağı çözümleyemezsiniz.

Sürüm bilgilerini bir metin (veya başka bir kaynak) dosyasına koyup JAR'a eklemeye çalışın ve okuyun. Kaynak dosya düzgün bir şekilde eklenmeli ve mekanizma ile okuyabiliyor olmalısınız.

+0

APK bölümünü tamamen unutmuştum. Sadece kütüphanenin bir kavanoz dosyasında olduğundan, APK'nın kendisinde paketleneceğini ve her şeyin hala işe yaradığını düşündüm. – Logan

+0

Biraz daha fazla açıklama ekledim ve bir platformda nasıl bağımsız bir şekilde üstesinden geleceğime dair bir fikir. – Stephan

+0

Bir 'version' dosyasını '/ res' içine yerleştirdikten sonra' Özellik 'sınıfını kullanarak, onu hem Android hem de standart Java’da mükemmel bir şekilde çalıştırarak okuyacağım. – Logan

2

Sen NullPointerException alıyorsanız.
Kaynak dosyanızı bir klasöre koyun ve kaynak klasörü olarak ayarlayın. Daha fazla bilgi için this answer on SO kontrol edin.
Ayrıca, geri yükleme klasörleri hakkında algılamalar için this SO answer'u da kontrol edebilirsiniz.

+0

Kaynağım dışında bir jar dosyasında bir sınıf var. :/ – Logan

+0

Kavanoz dosyası sınıf yolunuzda olduğu sürece sorun olmaz. Kavanoz dosyasını apk dosyanızla birlikte dışa aktardığınızdan emin misiniz? –

+1

Bunu kabul ediyorum, aksi takdirde kütüphanenin gerçek eti çalışmayacaktı (ki şu anda). – Logan

0

Sürüm bilgisini manifest dosyasında tutmak ve çalışma zamanında çıkarmak istiyorsunuz. Eğer öyleyse, Android'e hoşgeldiniz :-)

Karşılaştığınız sorunlardan çok daha iyi seçenekleriniz var. Bir Context ile

  • Kullanım PackageManager:

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

    Sonra PackageInfo ile size packageName, versionCode, versionName ... Bunlar AndroidManifest.xml tanımlanmıştır var.

  • Mağaza resources daki sürüm bilgileri gibi String, Integer ... Ayrıca Context kaynaklarını elde etmek gerekir:

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

O daha iyi olduğunu düşünüyorum.

+0

Bu Android'e özgü. Platform bağımsızlığına ihtiyacım var. Ama özünde yapmak istediğim şey bu. – Logan

İlgili konular