0

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 Answers1

0

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

Milind Barve
  • 410
  • 3
  • 5