java.lang.NoClassDefFoundError on older Android SDK versions

落花浮王杯 提交于 2021-01-27 03:52:37

问题


I released a version of my app to the Google Play and woke up this morning with a number of unhappy customers. The latest version of the app integrates support for a Bluetooth Low Energy (BTLE) heart rate monitor.

The app runs fine on Android 4.3 and 4.4 but crashes on 4.0, 4.1, and 4.2 with the following error.

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)

The error occurs when creating an Intent in a simple Onclick similar to the following…

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

After rushing out and buying a 4.2 tablet so I can replicate the issue, I’ve come to the conclusion that it has to do with this new version of the app supporting Bluetooth LE, which is enabled in SDK 4.3 and later. If I delete all references to Bluetooth in MainActivity then the crash goes away on 4.2 and earlier devices.

My understanding from reading the documentation was that one could write an app that includes Bluetooth LE functionality and it would run on older devices, just so long as one was careful not to execute BTLE code using something like the following...

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

Therefore my manifest.xml does not include the following as it would prevent download to older devices and I obviously want to maintain a single code base if possible ...

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

First question, is my assumption above being able to include BTLE code in SDKs prior to 4.3 correct? If not, do I really need to create two versions of the app... one for folks using 4.3 and later and one for everyone else?

There are many StackOverflow posts about java.lang.NoClassDefFoundError and I think I've read most of the relevant ones. Many suggest that I examine the Java Build Path to make sure that Android Private Libraries and Android Dependencies are checked. They are. Some suggest moving the gen folder before the src folder, but this doesn't seem to make a difference.

I'd post an image of the Eclipse Java Build Path but as this is my first post I don't have the 10 reputation points needed to insert an image, so here's another post that I followed... Android java.lang.NoClassDefFoundError

So, second question, any other thoughts about what could be wrong with the build path?

many thanks in advance.


Update... somehow by asking a question I got enough points to post images of the java build path. As @Ashoke points out I do think it has something to do with the wrong build path or support libraries.

Eclipse Order and Export

Eclipse Libraries


回答1:


Try getting all of the Ble related code into a separate class that you only instance at all if on a device with the necessary API levels. I think without this the call-backs could be leading to your issues.




回答2:


I found that defining the le callback statically in the activity gets an error, but inclosing it in a function with an api check will not produce the same error.

instead of:

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

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

I used:

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) {

            }
        };

    }
}



回答3:


now that you are using APIs that may not be available in older Android versions, make sure you are packaging the app with appropriate support library.

For example, see this android sample BluetoothLeGattSample. It uses below support 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




回答4:


This is normal to get this exception on <4.3 devices because BLE didn't exist, so your compiled code can't find the corresponding classes in the OS. Nothing wrong with your build path.

The best solution is indeed to protect your BLE code in a if clause, testing for BLE capability at runtime. You should also filter the OS version in the if like:

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

You should declare android:required="false" for this feature, it means that the application prefers to use the feature if present on the device, but that it is designed to function without the specified feature, if necessary.

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


来源:https://stackoverflow.com/questions/26790594/java-lang-noclassdeffounderror-on-older-android-sdk-versions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!