我正在尝试扫描BLE设备并在我的BLEFragment中显示它们。 但是,当我点击(R.id.scanButton)时出现错误:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.my.example, PID: 10990
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.view.View.getContext()' on a null object reference
at com.iothings.connect.BLEFragment$ListAdapter.getView(BLEFragment.java:231)
at android.widget.AbsListView.obtainView(AbsListView.java:2389)
at android.widget.ListView.makeAndAddView(ListView.java:1878)
at android.widget.ListView.fillDown(ListView.java:705)
at android.widget.ListView.fillFromTop(ListView.java:766)
at android.widget.ListView.layoutChildren(ListView.java:1673)
at android.widget.AbsListView.onLayout(AbsListView.java:2191)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1079)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:131)
at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1375)
at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:870)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1193)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2720)
at android.view.View.layout(View.java:16662)
at android.view.ViewGroup.layout(ViewGroup.java:5439)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2202)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1955)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1125)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6100)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographe
BLEFragment.java
public class BLEFragment extends Fragment implements ScanResultsConsumer {
private boolean ble_scanning = false;
//public Handler handler = new Handler();
private ListAdapter ble_device_list_adapter;
private BLEScanner ble_scanner;
private static final long SCAN_TIMEOUT = 5000;
private static final int REQUEST_LOCATION = 0;
private static String[] PERMISSIONS_LOCATION = {Manifest.permission.ACCESS_COARSE_LOCATION}; private boolean permissions_granted=false;
private int device_count=0;
private Toast toast;
static class ViewHolder {
public TextView text;
public TextView bdaddr;
}
@BindView(R.id.deviceList) ListView listView;
@BindView(R.id.scanButton) Button scanButton;
@OnClick(R.id.scanButton)
public void onScan(View view) {
if (!ble_scanner.isScanning()) {
Log.d(Constants.TAG, "Not currently scanning");
device_count=0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (getActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
permissions_granted = false;
requestLocationPermission();
} else {
Log.i(Constants.TAG, "Location permission has already been granted. Starting scanning.");
permissions_granted = true;
}
} else {
// the ACCESS_COARSE_LOCATION permission did not exist before M so....
permissions_granted = true;
}
startScanning();
} else {
Log.d(Constants.TAG, "Already scanning");
ble_scanner.stopScanning();
}
}
private void startScanning() {
if (permissions_granted) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
ble_device_list_adapter.clear();
ble_device_list_adapter.notifyDataSetChanged();
}
});
simpleToast(Constants.SCANNING,2000);
ble_scanner.startScanning(this, SCAN_TIMEOUT);
} else {
Log.i(Constants.TAG, "Permission to perform Bluetooth scanning was not yet granted");
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//returning our layout file
View view = inflater.inflate(R.layout.fragment_2_ble, container, false);
ButterKnife.bind(this, view);
setButtonText();
ble_device_list_adapter = new ListAdapter();
listView.setAdapter(ble_device_list_adapter);
ble_scanner = new BLEScanner();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (ble_scanning) {
ble_scanner.stopScanning();
}
BluetoothDevice device = ble_device_list_adapter.getDevice(position);
if (toast != null) {
toast.cancel();
}
Intent intent = new Intent(getActivity(), PeripheralControlActivity.class);
intent.putExtra(PeripheralControlActivity.EXTRA_NAME, device.getName());
intent.putExtra(PeripheralControlActivity.EXTRA_ID, device.getAddress());
startActivity(intent);
}
});
return view;
}
@Override
public void candidateBleDevice(final BluetoothDevice device, byte[] scan_record, int rssi) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
ble_device_list_adapter.addDevice(device);
ble_device_list_adapter.notifyDataSetChanged();
device_count++;
}
});
}
@Override
public void scanningStarted() {
setScanState(true);
}
@Override
public void scanningStopped() {
if (toast != null) {
toast.cancel();
}
setScanState(false);
}
private void setButtonText() {
String text="";
text = Constants.FIND;
final String button_text = text;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//((TextView) MainActivity.this.findViewById(R.id.scanButton)).setText(button_text);
}
});
}
private void setScanState(boolean value) {
ble_scanning = value;
Log.d(Constants.TAG,"Setting scan state to "+value);
scanButton.setText(value ? Constants.STOP_SCANNING : Constants.FIND);
}
public static class ListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> ble_devices;
public ListAdapter() {
super();
ble_devices = new ArrayList<BluetoothDevice>();
}
public void addDevice(BluetoothDevice device) {
if (!ble_devices.contains(device)) {
ble_devices.add(device);
}
}
public boolean contains(BluetoothDevice device) {
return ble_devices.contains(device);
}
public BluetoothDevice getDevice(int position) {
return ble_devices.get(position);
}
public void clear() {
ble_devices.clear();
}
@Override
public int getCount() {
return ble_devices.size();
}
@Override
public Object getItem(int i) {
return ble_devices.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
if (view == null) {
Context context = view.getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
view = inflater.inflate(R.layout.list_row, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) view.findViewById(R.id.textView);
viewHolder.bdaddr = (TextView) view.findViewById(R.id.bdaddr);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = ble_devices.get(i);
String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0) {
viewHolder.text.setText(deviceName);
} else {
viewHolder.text.setText("unknown device");
}
viewHolder.bdaddr.setText(device.getAddress());
return view;
}
}
private void requestLocationPermission() {
Log.i(Constants.TAG, "Location permission has NOT yet been granted. Requesting permission.");
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION)){
Log.i(Constants.TAG, "Displaying location permission rationale to provide additional context.");
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Permission Required");
builder.setMessage("Please grant Location access so this application can perform Bluetooth scanning");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
Log.d(Constants.TAG, "Requesting permissions after explanation");
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
}
});
builder.show();
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_LOCATION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_LOCATION) {
Log.i(Constants.TAG, "Received response for location permission request.");
// Check if the only required permission has been granted
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Location permission has been granted
Log.i(Constants.TAG, "Location permission has now been granted. Scanning.....");
permissions_granted = true;
if (ble_scanner.isScanning()) {
startScanning();
}
}else{
Log.i(Constants.TAG, "Location permission was NOT granted.");
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void simpleToast(String message, int duration) {
toast = Toast.makeText(getActivity(), message, duration);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//you can set the title for your toolbar here for different fragments different titles
getActivity().setTitle("BLE");
}
}
BLEScanner.java
public class BLEScanner {
private BluetoothLeScanner scanner = null;
private BluetoothAdapter bluetooth_adapter = null;
private Handler handler = new Handler();
private ScanResultsConsumer scan_results_consumer;
private Context context;
private boolean scanning = false;
private String device_name_start = "";
public void BleScanner(Context context) {
this.context = context;
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetooth_adapter = bluetoothManager.getAdapter();
// check bluetooth is available and on
if (bluetooth_adapter == null || !bluetooth_adapter.isEnabled()) {
Log.d(Constants.TAG, "Bluetooth is NOT switched on");
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
enableBtIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(enableBtIntent);
}
Log.d(Constants.TAG, "Bluetooth is switched on");
}
public void startScanning(final ScanResultsConsumer scan_results_consumer, long stop_after_ms) {
if (scanning) {
Log.d(Constants.TAG, "Already scanning so ignoring startScanning request");
return;
}
Log.d(Constants.TAG, "Scanning...");
if (scanner == null) {
scanner = bluetooth_adapter.getBluetoothLeScanner();
Log.d(Constants.TAG, "Created BluetoothScanner object");
}
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (scanning) {
Log.d(Constants.TAG, "Stopping scanning");
scanner.stopScan(scan_callback);
setScanning(false);
}
}
}, stop_after_ms);
this.scan_results_consumer = scan_results_consumer;
List<ScanFilter> filters;
filters = new ArrayList<ScanFilter>();
/*ScanFilter filter = new ScanFilter.Builder().setDeviceName("SP5").build();
filters.add(filter);*/
ScanSettings settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
setScanning(true);
scanner.startScan(filters, settings, scan_callback);
}
public void stopScanning() {
setScanning(false);
Log.d(Constants.TAG, "Stopping scanning");
scanner.stopScan(scan_callback);
}
private ScanCallback scan_callback = new ScanCallback() {
public void onScanResult(int callbackType, final ScanResult result) {
if (!scanning) {
return;
}
scan_results_consumer.candidateBleDevice(result.getDevice(), result.getScanRecord().getBytes(), result.getRssi());
}
};
public boolean isScanning() {
return scanning;
}
void setScanning(boolean scanning) {
this.scanning = scanning;
if (!scanning) {
scan_results_consumer.scanningStopped();
} else {
scan_results_consumer.scanningStarted(); }
}
}
我认为问题来自视图的getContext为null。 有关如何解决这个问题的任何想法?感谢
答案 0 :(得分:1)
ViewGroup viewGroup
不为空,因此您可以使用
viewGroup.getContext()
答案 1 :(得分:0)
您可以使用以下行在Fragment中获取上下文。
getActivity().getBaseContext();
使用上面的代码替换getView()
方法中的上下文。