Android应用程序在意图启动之前崩溃

时间:2017-08-06 14:05:27

标签: java android bluetooth bluetooth-lowenergy

我正在创建我的第一个Android应用程序,所以我真的是(android)开发的初学者。

应用程序的第一个特点是实现一个Activity(即BleActivity.java),当单击某个按钮时会调用它。 BleActivity应列出可用的BLE设备(使用tiSensorTag CC2650进行测试),稍后我想从设备中读取数据。

要让它发挥作用是一个相当大的挑战,因为大多数在线教程都是使用已弃用的API编写的。结合几个教程后,该应用程序正在运行!

应用中有一个我无法修复的错误:

当蓝牙关闭并且我触发BleActivity时,onResume()会检查蓝牙是否已启用(情况并非如此),如果不是,则会出现一个对话框请求用户打开蓝牙。

我可以看到对话框屏幕,但在我能够使用它之前,应用程序崩溃了。

BleActivity.java

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class BleActivity extends ListActivity {

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

    // see nested class LeDeviceListAdapter
    private LeDeviceListAdapter mLeDeviceListAdapter;

    private BluetoothAdapter mBluetoothAdapter;
    private static final int REQUEST_ENABLE_BT = 1;
    private static final long SCAN_PERIOD = 10000;
    private Handler mHandler;
    private boolean mScanning;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    private List<ScanFilter> filters;

    private static final String INFO = "ZINFO";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Check if BLE is supported
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
            finish();
        } else {
            Log.i(INFO, "onCreate: BLE is supported");
        }
        // Create a Handler to send and process Message Class and Runnable objects associated with a thread's MessageQueue.
        mHandler = new Handler();

        // Get BluetoothManager and BluetoothAdapter in order to conduct overall Bluetooth Management.
        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Initialize list view adapter
        mLeDeviceListAdapter = new LeDeviceListAdapter();
        setListAdapter(mLeDeviceListAdapter);

        //Check if permission for ACCESS_COARSE_LOCATION (AndroidManifest.xml) is granted.
        if (checkLocationPermission()) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, R.string.grant_permission, Toast.LENGTH_LONG).show();
                finish();
            } else {
                Log.i(INFO, "onResume: Permission for ACCESS_COARSE_LOCATION is granted");
            }
        }

        // Check if bluetoothAdapter is successfully obtained and if BLE is enabled.
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        } else {
            Log.i(INFO, "onResume: BLE is enabled");
        }
        // GET getBluetoothLeScanner(): This class provides methods to perform scan related operations for Bluetooth LE devices
        mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
        // Set scan settings
        settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).build();
        // Set device filter (null is allowed)
        filters = new ArrayList<ScanFilter>();

        // START SCAN FOR BLE DEVICES!
        scanLeDevice(true);
    }

    // When user denies prompt for enabling Bluetooth, the Activity is closed
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
                finish();
                return;
            }
        super.onActivityResult(requestCode, resultCode, data);
    }

    // Pause scanning for BLE devices */
    @Override
    protected void onPause() {
        super.onPause();
        scanLeDevice(false);
        mLeDeviceListAdapter.clear();
    }

    //Methods for permission check
    public boolean checkLocationPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
                new AlertDialog.Builder(this)
                        .setTitle(R.string.title_location_permission)
                        .setMessage(R.string.text_location_permission)
                        .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                ActivityCompat.requestPermissions(BleActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
                            }
                        })
                        .create()
                        .show();
            } else {
                // No explanation needed, we can request the permission.
                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission. ACCESS_COARSE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
            }
            return false;
        } else {
            return true;
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i(INFO, "onRequestPermissionsResult: PERMISSION_GRANTED");
                } else {
                    finish();
                }
            }

        }
    }

    // Methods for START & STOP scan
    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mLEScanner.stopScan(mScanCallback); //STOP SCANNING
                }
            }, SCAN_PERIOD); // Stops scanning after a pre-defined scan period.

            mScanning = true;
            mLEScanner.startScan(filters, settings, mScanCallback); //START SCANNING
        } else {
            mScanning = false;
            mLEScanner.stopScan(mScanCallback); //STOP SCANNING
        }
        if(mScanning == true) {
            //TODO: Implement code for when the app is scanning (green stoplight, turning wheel, etc.)
        } else {
            //TODO: Implement code for when the app is NOT scanning (red stoplight, idle wheel, etc.)
        }
    }
    // Bluetooth LE scan results are reported using these callbacks.
    private ScanCallback mScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            BluetoothDevice btDevice = result.getDevice();
            mLeDeviceListAdapter.addDevice(btDevice);
            mLeDeviceListAdapter.notifyDataSetChanged();        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }
        @Override
        public void onScanFailed(int errorCode) {
            Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };

    // ListAdapter for holding devices found through scanning.
    private class LeDeviceListAdapter extends BaseAdapter {
        private ArrayList<BluetoothDevice> mLeDevices;
        private LayoutInflater mInflator;

        public LeDeviceListAdapter() {
            super();
            mLeDevices = new ArrayList<BluetoothDevice>();
            mInflator = BleActivity.this.getLayoutInflater();
        }

        public void addDevice(BluetoothDevice device) {
            if(!mLeDevices.contains(device)) {
                mLeDevices.add(device);
            }
        }

        /*
        TODO: implement onListItemClick (see example code)
        public BluetoothDevice getDevice(int position) {
            return mLeDevices.get(position);
        }*/

        public void clear() {
            mLeDevices.clear();
        }

        @Override
        public int getCount() {
            return mLeDevices.size();
        }

        @Override
        public Object getItem(int i) {
            return mLeDevices.get(i);
        }

        @Override
        public long getItemId(int i) {
            return i;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder;
            // General ListView optimization code.
            if (view == null) {
                view = mInflator.inflate(R.layout.activity_ble, null);
                viewHolder = new ViewHolder();
                viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
                viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            BluetoothDevice device = mLeDevices.get(i);
            final String deviceName = device.getName();
            if (deviceName != null && deviceName.length() > 0)
                viewHolder.deviceName.setText(deviceName);
            else
                viewHolder.deviceName.setText(R.string.unknown_device);
                viewHolder.deviceAddress.setText(device.getAddress());

            return view;
        }
    }
    static class ViewHolder {
        TextView deviceName;
        TextView deviceAddress;
    }
}

非常感谢您的帮助,请记住,这是我的第一个应用,我还是业余/初学者。

logcat的:

08-06 16:21:39.152 5489-5489/nl.cargosys.iotcloudconnect E/AndroidRuntime: FATAL EXCEPTION: main
                                                                           Process: nl.cargosys.iotcloudconnect, PID: 5489
                                                                           java.lang.RuntimeException: Unable to pause activity {nl.cargosys.iotcloudconnect/nl.cargosys.iotcloudconnect.BleActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeScanner.stopScan(android.bluetooth.le.ScanCallback)' on a null object reference
                                                                               at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4179)
                                                                               at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4145)
                                                                               at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4119)
                                                                               at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4093)
                                                                               at android.app.ActivityThread.-wrap18(ActivityThread.java)
                                                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1654)
                                                                               at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                               at android.os.Looper.loop(Looper.java:154)
                                                                               at android.app.ActivityThread.main(ActivityThread.java:6776)
                                                                               at java.lang.reflect.Method.invoke(Native Method)
                                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
                                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
                                                                            Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeScanner.stopScan(android.bluetooth.le.ScanCallback)' on a null object reference
                                                                               at nl.cargosys.iotcloudconnect.BleActivity.scanLeDevice(BleActivity.java:179)
                                                                               at nl.cargosys.iotcloudconnect.BleActivity.onPause(BleActivity.java:121)
                                                                               at android.app.Activity.performPause(Activity.java:7148)
                                                                               at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1330)
                                                                               at android.app.ActivityThread.performPauseActivityIfNeeded(ActivityThread.java:4168)
                                                                               at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4145) 
                                                                               at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4119) 
                                                                               at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4093) 
                                                                               at android.app.ActivityThread.-wrap18(ActivityThread.java) 
                                                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1654) 
                                                                               at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                               at android.os.Looper.loop(Looper.java:154) 
                                                                               at android.app.ActivityThread.main(ActivityThread.java:6776) 
                                                                               at java.lang.reflect.Method.invoke(Native Method) 
                                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520) 
                                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410) 

1 个答案:

答案 0 :(得分:0)

在您的if条件下 -

if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) 

主要问题在于你的 -

mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
    // Set scan settings
    settings = new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_BALANCED).build();
    // Set device filter (null is allowed)
    filters = new ArrayList<ScanFilter>();

    // START SCAN FOR BLE DEVICES!
    scanLeDevice(true);

您检查适配器是否可用,如果没有,则启动另一个活动以获得结果,但您继续在扫描仪代码中执行操作并在其他人之后扫描设备。理想情况下,如果您100%确定已启用蓝牙,则应将上述代码放在else语句中,并且只启动扫描设备。

更新1

好的,所以此错误来自您调用onPause()方法的scanLeDevice(false);方法。现在在这个方法中你做mLEScanner.stopScan(mScanCallback);但是你的mLEScanner还没有被初始化,因为初始化代码在你的else语句中或在行中

之后
mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();

因此,如果您在方法中执行此操作会更好 -

if(mLEScanner!=null)
{
   mLEScanner.stopScan(mScanCallback); 
}