旧Android SDK版本上的java.lang.NoClassDefFoundError

问题描述:

我向Google Play发布了一个我的应用版本,并在今天早上与一些不满意的客户一起醒来。该应用程序的最新版本集成了对蓝牙低功耗(BTLE)心率监视器的支持。旧Android SDK版本上的java.lang.NoClassDefFoundError

该应用在Android 4.3和4.4上运行良好,但在4.0,4.1和4.2上崩溃,并出现以下错误。

FATAL EXCEPTION: main 
java.lang.NoClassDefFoundError: com.eiref.boatcoach.MainActivity 
    at com.eiref.boatcoach.WhatToDo.onClick(WhatToDo.java:274) 
    at android.view.View.performClick(View.java:4204) 
    at android.view.View$PerformClick.run(View.java:17355) 
    at android.os.Handler.handleCallback(Handler.java:725) 
    at android.os.Handler.dispatchMessage(Handler.java:92) 
    at android.os.Looper.loop(Looper.java:152) 
    at android.app.ActivityThread.main(ActivityThread.java:5132) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:511) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) 
    at dalvik.system.NativeStart.main(Native Method) 

创建一个简单的Intent的onclick类似下面的...

public void onClick(View v) { 
     Intent i = new Intent(this, MainActivity.class); 
     startActivity(i); 
} 

里冲了出来,并购买4.2平板电脑,所以我可以复制该问题后,当出现的错误,我来这个结论与它支持蓝牙LE的这个新版本的应用程序有关,后者在SDK 4.3及更高版本中启用。如果我在MainActivity中删除所有对蓝牙的引用,那么4.2和更早版本的设备会崩溃。

我从阅读文档的理解是,人们可以编写一个包含蓝牙LE功能的应用程序,它可以在较旧的设备上运行,只要有人注意不要使用类似以下内容执行BTLE代码...

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) return; 
    BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); 
    mBluetoothAdapter = manager.getAdapter(); 
//etc. 

因此我的manifest.xml不包括以下内容,因为它会阻止下载到旧设备,我当然希望保持如果可能的话一个代码库...

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />  

第一个问题,我上面的假设是否能够在4.3之前的SDK中包含BTLE代码正确?如果没有,我真的需要创建两个版本的应用程序...一个人使用4.3和更高版本,其他人一个?

有很多关于java.lang.NoClassDefFoundError的*文章,我想我已经阅读了大部分相关的文章。许多人建议我检查Java构建路径以确保Android私有库和Android依赖项已被选中。他们是。一些人建议在src文件夹之前移动gen文件夹,但这似乎没有什么区别。

我会发布Eclipse Java Build Path的图像,但是因为这是我的第一篇文章,我没有插入图像所需的10个信誉点,所以这里是我遵循的另一篇文章... Android java.lang.NoClassDefFoundError

所以,第二个问题,关于什么可能是错误的构建路径的任何其他想法?

非常感谢提前。


更新...以某种方式通过问一个问题我有足够的观点发布java构建路径的图像。正如@Ashoke所指出的,我认为它与错误的构建路径或支持库有关。

Eclipse Order and Export

Eclipse Libraries

+0

请问您的onClick内相同的代码上> = 4.3运行或者是有根据的Android版本,另一个代码路径? – 2014-11-06 22:40:30

+0

你绝对不应该需要两个版本的应用程序。至于使用功能标签,我会建议你*包括它,但设置'android:required =“false”'。我不认为这是根本问题,但无论如何,这是很好的做法。 – kcoppock 2014-11-06 22:44:56

+0

@MichaelKrause - 是不同Android版本的完全相同的代码路径。 – 2014-11-07 15:02:23

这是正常的,因为BLE不存在获得对< 4.3设备此异常,所以你的编译代码找不到在OS的相应类。 您的构建路径没有错。

最好的解决方案确实是在if子句中保护您的BLE代码,在运行时测试BLE功能。你也应该在过滤OS版本,如果这样的:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {...} 

你应该声明android:required="false"此功能,这意味着应用程序更倾向于如果存在使用该功能的设备上,但它被设计成起没有指定的功能,如有必要。

<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" /> 
+0

感谢您的反馈。然而,问题在于Android版本 2014-11-07 15:11:16

+0

我想你还应该添加一个操作系统检查,这将确保在编译时低操作系统版本没有达到该代码(我更新了答案)。 – Murphy 2014-11-07 17:32:48

现在您正在使用的API可能无法在较旧的Android版本,请确保您的包装与适当的支持库的应用程序。例如,见android sample BluetoothLeGattSample。它使用下面的支持lib。

dependencies { 
     // Add the support lib that is appropriate for SDK 18 
     compile "com.android.support:support-v13:19.0.+" 
    } 

see android docs for eclipse instructions for support library setup

+0

Ashoke - 感谢您的建议。我尝试了android-support-v13.jar到Eclipse构建路径,但没有喜悦。 – 2014-11-07 16:01:51

尝试让所有的竹叶提取相关的代码到一个单独的类,你唯一的实例在所有如果有必要的API级别的设备上。我认为如果没有这个回调可能导致你的问题。

我发现在活动中静态地定义le回调会得到一个错误,但是用api检查将它放入函数中并不会产生相同的错误。

代替:

@TargetApi(Build.VERSION_CODES.LOLLIPOP){ 
    public class RouteMapActivity extends ActionBarActivity 

    private BluetoothAdapter.LeScanCallback mScanCallback = new ScanCallback() {...} 

我用:

private void setUpLeCallbacks(){ 


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     settings = new ScanSettings.Builder() 
       .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) 
       .build(); 

     for (BTDeviceName device : mTestPointsToRead) { 
      ScanFilter filter = new ScanFilter.Builder().setDeviceAddress(device.le_serial).build(); 
      filters.add(filter); 
     } 

     mScanCallback = new ScanCallback() { 
      @Override 
      public void onScanResult(int callbackType, ScanResult result) { 
       super.onScanResult(callbackType, result); 
      } 

      @Override 
      public void onScanFailed(int errorCode) { 
       super.onScanFailed(errorCode); 
      } 
     }; 
    }else { 
     mLeScanCallback= new BluetoothAdapter.LeScanCallback() { 

      @Override 
      public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { 

      } 
     }; 

    } 
} 
+0

你是如何添加全局变量而不从dalivk获取VFY警告的? – 2016-03-28 21:00:06

+1

@TargetApi(Build.VERSION_CODES.LOLLIPOP)重写lint错误。 – TacoEater 2016-03-28 22:25:11