我需要在蓝牙扫描时发出通知,如果我得到任何设备,即使我的应用程序没有在后台运行。我在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)
提前感谢你,
答案 0 :(得分:0)
将调用转移到startScan(
)从构造函数转移到onCreate()
方法:
@Override
public void onCreate() {
super.onCreate();
startScan();
}
由于getUrl()
是由startScan()
启动的扫描回调调用的,因此服务的上下文可能尚未完全初始化,从而导致空指针异常。作为一般规则,在组件的构造函数(Activity,Service等)中调用Android框架是不安全的。