【问题标题】:Android: adding ScanCallback gives me "Unfortunately, App has stopped." can't find MainActivityAndroid:添加 ScanCallback 给我“不幸的是,应用程序已停止。”找不到主活动
【发布时间】:2015-09-16 01:12:57
【问题描述】:

我对 Android 开发非常陌生。我看过一些 youtube 视频并阅读了一些文档。今天是第五天,所以请耐心等待。我正在尝试构建一个 BluetoothLE 应用程序。我从here 窃取了一些代码,但是当我尝试在我的设备上运行时。我收到“不幸的是,(应用程序名称)已停止”消息。在注释掉不同的代码块后,我将其固定在以下声明中:

private ScanCallback mScanCallback = new ScanCallback() {};

如果我包含该行,它会崩溃。如果我不这样做,它就会活着。这是完整的 Java 类:

package com.tremor.creech.bluetoothExample;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.util.List;
@TargetApi(21)
public class MainActivity extends AppCompatActivity {

    private BluetoothAdapter mBluetoothAdapter;
    private int REQUEST_ENABLE_BT = 1;
    private Handler mHandler;
    private static final long SCAN_PERIOD = 10000;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothGatt mGatt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private ScanCallback mScanCallback = new ScanCallback() { }; //If I include this line, then it crashes. If I take it out, then I see my Hello World activity.
}

LogCat 错误:

09-15 19:16:17.503    1878-1878/com.roberts.croberts.mantis E/dalvikvm﹕ Could not find class 'com.roberts.croberts.mantis.MainActivity$1', referenced from method com.roberts.croberts.mantis.MainActivity.<init>
09-15 19:16:17.523    1878-1878/com.roberts.croberts.mantis E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.roberts.croberts.mantis, PID: 1878
    java.lang.NoClassDefFoundError: com.roberts.croberts.mantis.MainActivity$1
            at com.roberts.croberts.mantis.MainActivity.<init>(MainActivity.java:154)
            at java.lang.Class.newInstanceImpl(Native Method)
            at java.lang.Class.newInstance(Class.java:1208)
            at android.app.Instrumentation.newActivity(Instrumentation.java:1061)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2119)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2252)
            at android.app.ActivityThread.access$800(ActivityThread.java:139)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
            at dalvik.system.NativeStart.main(Native Method)
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ Thread state: conn_id=0, state=RX_THREAD_WAIT_READ
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ Thread state: conn_id=0, state=RX_THREAD_CLIENT_TX
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ qmi_qmux: TX/RX - RX 30 bytes on conn_id=0
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ 01 1D 00 80 03 01 04 00 00 51 00 11 00 10 03 00
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ BA 0E 00 11 08 00 BE 08 00 07 00 00 00 00
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ qmuxd: TX message on fd=29, to qmux_client_id=2, len=64
09-15 19:16:18.023      461-717/? E/Diag_Lib﹕ Thread state: conn_id=0, state=RX_THREAD_WAIT_POLL
09-15 19:16:18.033      454-454/? E/Parcel﹕ Reading a NULL string not supported here.
09-15 19:16:18.033      454-454/? E/Parcel﹕ Reading a NULL string not supported here.
09-15 19:16:18.033      454-454/? E/Parcel﹕ Reading a NULL string not supported here.
09-15 19:16:18.033      454-454/? E/Parcel﹕ Reading a NULL string not supported here.

【问题讨论】:

  • Scancallback 是 Android 21 (lollipop) 的一部分,您是否尝试针对以前版本的 android 运行您的代码?
  • 我的手机运行的是 android 4.4.2,api 版本 19 或 20,我想我认为 @TargetApi(21) 装饰器应该可以解决我所有的问题。
  • @TargetApi 用于 Lint,因此 IDE 不会打扰您。 developer.android.com/reference/android/annotation/…

标签: android bluetooth android-ble


【解决方案1】:

不幸的是,要在 android 下构建 BLE 应用程序,您必须将 android Jelly Bean MR2(18) + Kitkat(19) 和 Lollipop (21+) 分开。

因为你才刚刚开始,所以我给你概述一下如何检查。

首先为JellyBean/Kitkat 和lollipop 声明这些变量。

//For Jelly Bean MR2 and Kitkat
private BluetoothAdapter.LeScanCallback leScanCallback;

//For Lollipop.
private BluetoothLeScanner bluetoothLeScanner;
private ScanCallback scanCallback;

由于它们没有启动,因此在运行应用程序时不会出现错误。为了启动目标api是什么,可以使用Build:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    //JellyBean/Kitkat
} else {
    //lollipop+
}

另外不要忘记检查手机是否真的具有 Ble 功能,是否需要将 uses 功能添加到清单中:

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

并通过PackageManager 进行检查:

boolean hasBle = getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);

必须执行此检查,因为某些手机(如galaxy nexus)可以使用果冻豆MR2,但没有BLE功能)

最后的建议是,要非常小心回调泄漏并正确停止/删除回调;)

【讨论】:

  • 是否需要同时检查清单和 packageManager?还是在清单中设置 required="true" 就足够了?
  • 我认为清单更适合 Google Play 允许或不允许某人下载该应用程序。例如,您仍然可以在非 ble 手机上从 android studio 安装,即使是必需的也是如此。所以请务必与包管理器联系;)developer.android.com/guide/topics/manifest/…
【解决方案2】:

在此线程上回复为时已晚,但我想分享我的想法,以克服 API 21 以下设备上的崩溃。ScanCallback 类得到 API 21 的支持。所以当你编写代码来实现 ScanCallback在您的扫描代码中,它会导致情人 API 崩溃。我已通过以下方式修复它:

我创建了一个新的抽象类,它扩展了 ScanCallback 类,如下所示:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)  
public abstract class AppScanCallback extends ScanCallback {}

现在我在我的 BluetoothService 类中使用这个类实例,如下所示:

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private AppScanCallback mScanCallback;

并使用这个变量如下:

public void startBleScan() {
    if (isEnabled()) {
        if (Build.VERSION.SDK_INT < 21) {
            _bluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mLEScanner = _bluetoothAdapter.getBluetoothLeScanner();
            settings = new ScanSettings.Builder()
                    .build();
            filters = new ArrayList<>();

            mScanCallback = new AppScanCallback() {
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
                    if (Build.VERSION.SDK_INT >= 21) {
                        BluetoothDevice btDevice = result.getDevice();
                        onLeScanResult(btDevice, result.getScanRecord().getBytes());
                    }
                }

                @Override
                public void onBatchScanResults(List<ScanResult> results) {
                    for (ScanResult sr : results) {
                        Log.i("ScanResult - Results", sr.toString());
                    }
                }
                @Override
                public void onScanFailed(int errorCode) {
                    Log.e("Scan Failed", "Error Code: " + errorCode);
                }
            };
            mLEScanner.startScan(filters, settings, mScanCallback);
        }

    }
}

并停止扫描

public void stopBLEScan() {;
        if (Build.VERSION.SDK_INT < 21) {
            _bluetoothAdapter.stopLeScan(mLeScanCallback);
        } else {
            mLEScanner.stopScan(mScanCallback);
        }
}

希望对你有所帮助。

【讨论】:

    【解决方案3】:

    不是这个

       private ScanCallback mScanCallback = new ScanCallback() { }; 
    

    试试这个

      private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {};
    

    【讨论】:

    • API19 和 API21 是否可以在同一个类中同时使用?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多