英文:
Scanning Bluetooth Devices to ArrayList Results in NullPointerException
问题
我正在尝试学习使用Java开发Android应用,以处理蓝牙设备。
在扫描蓝牙设备时,应用程序崩溃,并显示以下错误:
2020-09-20 00:59:06.684 14049-14049/com.fm.basic_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.fm.basic_app, PID: 14049
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:445)
at android.widget.ArrayAdapter.getView(ArrayAdapter.java:407)
...
我不确定如何根据上述内容来调试应用程序。以下是触发蓝牙扫描的方法:
bt_disc = (Button) findViewById(R.id.disc_dev);
完整的代码:
// ...(代码省略,与问题中提供的代码一致)
列出已配对的设备没问题,但是列出已发现的设备会导致应用程序崩溃...
任何见解将不胜感激,提前感谢!
英文:
I'm trying to learn on developing Android with Java, to handle Bluetooth devices.
When scanning for Bluetooth devices, the application crashed, with the below error:
2020-09-20 00:59:06.684 14049-14049/com.fm.basic_app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.fm.basic_app, PID: 14049
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
at android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.java:445)
at android.widget.ArrayAdapter.getView(ArrayAdapter.java:407)
at android.widget.AbsListView.obtainView(AbsListView.java:2388)
at android.widget.ListView.makeAndAddView(ListView.java:2054)
at android.widget.ListView.fillDown(ListView.java:788)
at android.widget.ListView.fillFromTop(ListView.java:849)
at android.widget.ListView.layoutChildren(ListView.java:1800)
at android.widget.AbsListView.onLayout(AbsListView.java:2187)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:444)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1791)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1635)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1544)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:761)
at android.view.View.layout(View.java:19663)
at android.view.ViewGroup.layout(ViewGroup.java:6075)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2548)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2264)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1444)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6843)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:778)
at android.view.Choreographer.doFrame(Choreographer.java:713)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6518)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
I am not sure how to debug the application based on the above, here's the method where Bluetooth scans are triggered via:
bt_disc = (Button) findViewById(R.id.disc_dev);
Full code:
package com.fm.basic_app; //package name
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; //packages import
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Set;
public class MainActivity extends AppCompatActivity { //main activity
ListView list_view;
Button bt_on, bt_off, bt_scan, bt_disc; //declare button object
BluetoothAdapter devBT; //declare BT adapter object
Intent bt_enabled;
IntentFilter discover_dev;
int bt_req_code;
int lc_coarse_req_code;
int lc_fine_req_code;
ArrayList<String> discovered_devices = new ArrayList<String>();
ArrayAdapter<String> dev_adapt;
@Override //override the current class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().getDecorView().setBackgroundColor(Color.LTGRAY); //change background color
bt_on = (Button) findViewById(R.id.bt_on); //declare button on view
bt_off = (Button) findViewById(R.id.bt_off);
bt_scan = (Button) findViewById(R.id.bt_scan);
list_view = (ListView) findViewById(R.id.lst_view);
bt_disc = (Button) findViewById(R.id.disc_dev);
devBT = BluetoothAdapter.getDefaultAdapter(); //try to get default adapter for BT
bt_enabled = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
bt_req_code = 1;
lc_coarse_req_code = 1;
lc_fine_req_code = 1;
req_perm_method();
bt_on_method();
bt_off_method();
bt_scan_method();
bt_disc_method();
}
private void req_perm_method() {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, lc_fine_req_code);
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, lc_fine_req_code);
}
}
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, lc_coarse_req_code);
} else {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, lc_coarse_req_code);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
}
if (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.ACCESS_COARSE_LOCATION ) == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
private void bt_disc_method() {
bt_disc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Discovering Devices", Toast.LENGTH_LONG).show();
devBT.startDiscovery();
}
});
discover_dev = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(dev_discover, discover_dev);
dev_adapt = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, discovered_devices);
list_view.setAdapter(dev_adapt);
}
BroadcastReceiver dev_discover = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String bt_action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(bt_action)){
BluetoothDevice bt_dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
discovered_devices.add(bt_dev.getName());
dev_adapt.notifyDataSetChanged();
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dev_discover);
}
private void bt_scan_method() {
bt_scan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "Paired Devices Will Be Shown", Toast.LENGTH_SHORT).show();
Set<BluetoothDevice> btpoll = devBT.getBondedDevices();
String[] devicelist = new String[btpoll.size()];
int index = 0;
if(btpoll.size()>0){
for (BluetoothDevice alldevices: btpoll){
devicelist[index] = alldevices.getName();
index++;
}
ArrayAdapter<String> devicearray = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, devicelist);
list_view.setAdapter(devicearray);
}
}
});
}
private void bt_off_method() {
bt_off.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(devBT.isEnabled()){
devBT.disable();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if(requestCode == bt_req_code){
if(resultCode == RESULT_OK){
Toast.makeText(this, "Bluetooth is Enabled", Toast.LENGTH_LONG).show();
}else if (resultCode == RESULT_CANCELED){
Toast.makeText(this, "Bluetooth Enable Cancelled", Toast.LENGTH_SHORT).show();
}
}
}
private void bt_on_method() {
bt_on.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(devBT == null){
Toast.makeText(MainActivity.this, "Device Does Not Support Bluetooth", Toast.LENGTH_LONG).show();
}else{
if(!devBT.isEnabled()){
startActivityForResult(bt_enabled, bt_req_code);
}
}
}
});
}
}
Listing paired devices is fine, but listing discovered devices would crash the application....
Any insights would be appreciated, thanks in advance!
答案1
得分: 0
以下是翻译好的部分:
当list_view适配器尝试渲染已发现的设备名称时,异常会发生。
对于蓝牙设备,很多情况下返回的名称是null。因此您的代码,在您尝试获取设备名称并将其添加到已发现的设备数组中时,可能会包含null条目。尝试添加空值检查
BluetoothDevice bt_dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if( bt_dev.getName() != null){
discovered_devices.add(bt_dev.getName());
}
else{
discovered_devices.add(bt_dev.getAddress()); // show device address instead
}
dev_adapt.notifyDataSetChanged();
这应该修复崩溃问题。如果有帮助,请告诉我。
英文:
The exception is coming when the list_view adapter is trying to render the devices names discovered.
For Bluetooth Devices many times the name returned is null. hence your code where you are trying to get device name and adding it to discovered_devices array, may contain null entries. Try adding a null check
BluetoothDevice bt_dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if( bt_dev.getName() != null){
discovered_devices.add(bt_dev.getName());
}
else{
discovered_devices.add(bt_dev.getAddress()); // show device address instead
}
dev_adapt.notifyDataSetChanged();
This should fix the crash. let me know if this is helpful
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论