通知发件人中的空指针异常

时间:2016-02-05 12:06:47

标签: android bluetooth-lowenergy

我需要在蓝牙扫描时发出通知,如果我得到任何设备,即使我的应用程序没有在后台运行。我在Intent line

中发送通知时遇到空指针异常
Intent targetIntent = new Intent(this, BeaconsActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);

我的项目完整代码如下:

public class BleService extends Service {

public static final String TAG = "BleService";
static final int MSG_STATE_CHANGED = 1;

private final List<Messenger> mClients = new LinkedList<>();
private final Map<String, BluetoothDevice> mDevices = new HashMap<>();

public enum State {
    UNKNOWN,
    IDLE,
    SCANNING,
    BLUETOOTH_OFF,
    CONNECTING,
    CONNECTED,
    DISCONNECTING
}

private BluetoothAdapter mBluetooth = null;
private State mState = State.UNKNOWN;


BluetoothLeScanner scanner;

private ScanSettings SCAN_SETTINGS;
private static final byte EDDYSTONE_URL_FRAME_TYPE = 0x10;
private static ParcelUuid EDDYSTONE_SERVICE_UUID;
private static ScanFilter EDDYSTONE_SCAN_FILTER;

public BleService() {
    Log.e("BleService", "BleService");
    startScan();
}

@Override
public IBinder onBind(Intent intent) {
    return mBinder;
}

public class LocalBinder extends Binder {
}

private final IBinder mBinder = new LocalBinder();

@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

private void startScan() {
    mDevices.clear();
    setState(State.SCANNING);

    mBluetooth = BluetoothAdapter.getDefaultAdapter();
    scanner = mBluetooth.getBluetoothLeScanner();
    List<ScanFilter> SCAN_FILTERS = buildScanFilters();

    if (!mBluetooth.isEnabled()) {
        setState(State.BLUETOOTH_OFF);
        Log.e("mBluetooth2", "mBluetooth2 : OFF");
    } else {
        SCAN_SETTINGS = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(0).build();
        scanner.startScan(SCAN_FILTERS, SCAN_SETTINGS, scanCallback);
    }
}

private static List<ScanFilter> buildScanFilters() {

    EDDYSTONE_SERVICE_UUID = ParcelUuid.fromString("0000FEAA-0000-1000-8000-00805F9B34FB");
    EDDYSTONE_SCAN_FILTER = new ScanFilter.Builder().setServiceUuid(EDDYSTONE_SERVICE_UUID).build();

    List<ScanFilter> scanFilters = new ArrayList<>();
    scanFilters.add(EDDYSTONE_SCAN_FILTER);

    return scanFilters;
}

ScanCallback scanCallback = new ScanCallback() {
    @Override
    public void onScanResult(int callbackType, ScanResult result) {

        ScanRecord scanRecord = result.getScanRecord();

        if (scanRecord == null) {
            Log.e(TAG, "Null ScanRecord for device " + result.getDevice().getAddress());
            return;
        }

        byte[] serviceData = scanRecord.getServiceData(EDDYSTONE_SERVICE_UUID);
        if (serviceData == null) {
            return;
        }

        if (serviceData[0] != EDDYSTONE_URL_FRAME_TYPE) {
            return;
        }

        int rssiValue = result.getRssi();

        byte[] fullHex = Arrays.copyOfRange(serviceData, 1, 10);
        Log.e("Full Hex: ", Utils.toHexString(fullHex));

        getUrl(serviceData, rssiValue);

    }

    @Override
    public void onScanFailed(int errorCode) {
        Log.e(TAG, "onScanFailed errorCode " + errorCode);
    }
};

private Beacon getUrl(byte[] hex, int rssiValue) {

    Beacon beacon = null;

    byte[] txPower = Arrays.copyOfRange(hex, 1, 2);
    Log.e("txPower", "txPower : " + Utils.toHexString(txPower));

    byte[] schemePrefixByte = Arrays.copyOfRange(hex, 2, 3);
    Log.e("schemePrefixByte", "schemePrefixByte :" + Utils.toHexString(schemePrefixByte));
    String schemePrefix = getSchemePrefix(Utils.toHexString(schemePrefixByte));

    byte[] urlByte = Arrays.copyOfRange(hex, 3, 9);
    String url = StringToHex.convertHexToString(Utils.toHexString(urlByte));

    byte[] domainExtensionByte = Arrays.copyOfRange(hex, 9, 10);
    String domainExtension = getDomainExtension(Utils.toHexString(domainExtensionByte));

    if (schemePrefix != null && url != null && domainExtension != null) {

        beacon = new Beacon("EDDYSTONE", schemePrefix, url, domainExtension, rssiValue);

        Intent targetIntent = new Intent(this, BeaconsActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        Notification noti = new Notification.Builder(this)
                .setContentTitle("New Offer @New Store")
                .setContentText("URL : " + beacon.getFullURL())
                .setLargeIcon(((BitmapDrawable) getResources().getDrawable(R.drawable.ic_notification_large, getTheme())).getBitmap())
                .setSmallIcon(R.drawable.beacon_gray)
                .setContentIntent(contentIntent).build();

        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        noti.flags |= Notification.FLAG_AUTO_CANCEL;

        notificationManager.notify(0, noti);

        Log.e("url", "url : " + beacon.getFullURL());

    }


    return beacon;
}

private String getSchemePrefix(String hex) {
    String schemePrefix = null;
    switch (hex) {
        case "00":
            schemePrefix = "http://www.";
            break;
        case "01":
            schemePrefix = "https://www.";
            break;
        case "02":
            schemePrefix = "http://";
            break;
        case "03":
            schemePrefix = "https://";
            break;
    }

    return schemePrefix;
}

private String getDomainExtension(String hex) {
    String domainExtension = null;
    switch (hex) {
        case "00":
            domainExtension = ".com/";
            break;
        case "01":
            domainExtension = ".org/";
            break;
        case "02":
            domainExtension = ".edu/";
            break;
        case "03":
            domainExtension = ".net/";
            break;
        case "04":
            domainExtension = ".info/";
            break;
        case "05":
            domainExtension = ".biz/";
            break;
        case "06":
            domainExtension = ".gov/";
            break;
        case "07":
            domainExtension = ".com";
            break;
        case "08":
            domainExtension = ".org";
            break;
        case "09":
            domainExtension = ".edu";
            break;
        case "0a":
            domainExtension = ".net";
            break;
        case "0b":
            domainExtension = ".info";
            break;
        case "0c":
            domainExtension = ".biz";
            break;
        case "0d":
            domainExtension = ".gov";
            break;
    }

    return domainExtension;
}

private void setState(State newState) {
    if (mState != newState) {
        mState = newState;
        Message msg = getStateMessage();
        if (msg != null) {
            sendMessage(msg);
        }
    }
}

private Message getStateMessage() {
    Message msg = Message.obtain(null, MSG_STATE_CHANGED);
    if (msg != null) {
        msg.arg1 = mState.ordinal();
    }
    return msg;
}

private void sendMessage(Message msg) {
    for (int i = mClients.size() - 1; i >= 0; i--) {
        Messenger messenger = mClients.get(i);
        if (!sendMessage(messenger, msg)) {
            mClients.remove(messenger);
        }
    }
}

private boolean sendMessage(Messenger messenger, Message msg) {
    boolean success = true;
    try {
        messenger.send(msg);
    } catch (RemoteException e) {
        Log.w(TAG, "Lost connection to client", e);
        success = false;
    }
    return success;
}

}

我的Logcat错误如下所示:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.cosmonet.advertisementapp, PID: 30703
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
    at android.content.ContextWrapper.getPackageName(ContextWrapper.java:131)
    at android.content.ComponentName.<init>(ComponentName.java:77)
    at android.content.Intent.<init>(Intent.java:4006)
    at com.cosmonet.advertisementapp.beacons.BleService.getUrl(BleService.java:235)
    at com.cosmonet.advertisementapp.beacons.BleService.access$100(BleService.java:40)
    at com.cosmonet.advertisementapp.beacons.BleService$1.onScanResult(BleService.java:202)
    at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:330)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5312)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)

提前感谢你,

1 个答案:

答案 0 :(得分:0)

将调用转移到startScan()从构造函数转移到onCreate()方法:

@Override
public void onCreate() {
    super.onCreate();
    startScan();
}

由于getUrl()是由startScan()启动的扫描回调调用的,因此服务的上下文可能尚未完全初始化,从而导致空指针异常。作为一般规则,在组件的构造函数(Activity,Service等)中调用Android框架是不安全的。