onLeScan никогда не называется Android

У меня есть приложение на iPad, которое отправляет информацию Bluetooth LE вместо имени устройства. Я пытаюсь зафиксировать эту информацию в своем коде Android и каким-то образом обновить пользовательский интерфейс. В основном мне нужно постоянно сканировать устройства и использовать «имя устройства» в соответствии с моим протоколом для обновления пользовательского интерфейса Android. Я знаю, что это неправильный способ, и я планирую реорганизовать оба приложения, чтобы они правильно использовали Bluetooth LE, но мне нужно сделать это в ближайшее время, а сейчас у меня нет времени.

В моем коде ниже я знаю, что scanLeDevices вызывается из-за некоторых журналов, которые я ввел, но оператор печати, который у меня есть в onLeScan, никогда не вызывается. Кто-нибудь может сказать мне, почему? Я давно застрял на этом...

public class MainActivity extends Activity {
    private static final String TAG = "...";
    List<String> listItems=new ArrayList<String>();
    ArrayAdapter<String> adapter;

    BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    TextView mainView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.activity_main);
        setProgressBarIndeterminate(true);

        mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        mBluetoothAdapter = mBluetoothManager.getAdapter();
        mainView = (TextView) findViewById(R.id.main_view);

        scanLeDevice(true);     
    }

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

        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            //Bluetooth is disabled
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivity(enableBtIntent);
            finish();
            return;
        }

        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, "No LE Support.", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

        scanLeDevice(true);
    }

    private static final long SCAN_TIME = 1000;
    boolean mScanning = false;
    private void scanLeDevice(final boolean enable) {
        Log.i(null, "Inside scanLeDevice");
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    Log.i(null, "Calling stopLeScan");
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_TIME);

            mScanning = true;
            Log.i(null, "Calling startLeScan");
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(final BluetoothDevice device, int rssi,
                byte[] scanRecord) {
            runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   Log.i(null, "INSIDE ONLESCAN");
                   //DO MY WORK
               }
           });
       }
    };
}

person duke_    schedule 02.02.2014    source источник
comment
При вызове scanLeDevice(true) в onResume достаточно. Пожалуйста, удалите тот, что в onCreate.   -  person Jorge Gil    schedule 09.09.2015


Ответы (3)


Я не могу точно сказать, что не так, но вот несколько идей:

  1. проверить возвращаемое значение startLeScan(). Если startLeScan() возвращает false, сканирование не началось, вероятно, из-за проблем с правами доступа. См. http://developer.android.com/guide/topics/connectivity/bluetooth-le.html#permissions
  2. увеличьте SCAN_TIME. Например, SCAN_TIME = 10000. Если SCAN_TIME короче интервала вещания вашего маяка, ваша программа может его не обнаружить.
  3. удалите вызов scanLeDevice() из onCreate(). Как бы то ни было, когда эта программа запускается, onCreate() вызывает scanLeDevice(), затем почти сразу же вызывается onResume() и снова вызывает scanLeDevice(). Я не знаю, что произойдет, если вы вызовете startLeScan(), когда сканирование уже запущено, но я думаю, что было бы хорошо этого не делать.
  4. Перезагрузите Android-устройство. Я обнаружил, что это полезно во время разработки BLE, когда мое приложение BLE перестает работать.
  5. Убедитесь, что другое приложение для обнаружения BLE может видеть ваше устройство BLE.
person Bradford Needham    schedule 03.02.2014
comment
Большое спасибо. Удаление вызова функции из onCreate() и перезагрузка моего устройства помогли. Столько часов потрачено впустую. Я бы хотел, чтобы это позволило мне проголосовать за вас, но я думаю, что этого не произойдет, пока я не получу больше представителей. Спасибо еще раз! - person duke_; 04.02.2014
comment
Я не хочу перезагружать устройство. Есть ли другое решение? Моя проблема в том, что startLeScan иногда возвращает false. - person Raj Trivedi; 28.07.2015
comment
Я позаботился обо всех вышеперечисленных факторах. Но я столкнулся с этой проблемой. вопросы/31834232/startlescan-returns-false - person Raj Trivedi; 05.08.2015
comment
Для тех, кто, как и я, в настоящее время потратил часы впустую, я бы добавил 6-й случай: более новые API Android требуют, чтобы службы определения местоположения были включены также при сканировании BLE. Так что проверь и это. ;) - person zed; 16.12.2016
comment
У меня также была проблема с разрешением местоположения. В более новых версиях вам необходимо иметь разрешение на грубое определение местоположения. - person m.hashemian; 07.07.2017
comment
поскольку вы упомянули перезагрузку - переключение режима полета - это хороший способ отменить ожидающие или зависшие операции Bluetooth, которые мешают вам получать результаты или другие забавные дела. - person Saik Caskey; 19.10.2018

1. Сначала проверьте разрешение, например (нужен только ACCESS_COARSE_LOCATION):

 private void checkPermission() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;

    String[] permissions = new String[]{
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.CAMERA,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE};

    if (checkSelfPermission(permissions[0]) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(permissions, REQUEST_ENABLE_LOCATION);
    }
}

2. если вы используете gradle, проверьте targetSdkVersion, когда я устанавливаю targetSdkVersion=24, onLeScan никогда не вызывается, но я меняю targetSdkVersion = 22, вызывается onLeScan, я не знаю почему, мне требуются часы, чтобы найти эту проблему.

person Jishi Chen    schedule 11.10.2016

Вам нужны ОБА разрешения в вашем AndroidManifest.xml, чтобы сканировать устройства:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
person mschmoock    schedule 17.10.2014
comment
Что он сказал. Однажды я написал приложение только с одним из этих разрешений, и оно молча отказалось и никогда не вызывало мой обратный вызов. Добавление обоих устранило проблему. - person swooby; 07.04.2015
comment
Я использовал вышеуказанные разрешения, но все равно получаю это stackoverflow.com/questions/31834232/startlescan- возвращает-false проблема - person Raj Trivedi; 05.08.2015
comment
Тоже нашел эту проблему. Я установил BLUETOOTH в качестве разрешения без АДМИНИСТРАТОРА. При использовании Xamarin, вызове StartLeScan и переносе вызова в блок try/catch метод просто завершается с ошибкой. Добавление BLUETOOTH_ADMIN обеспечивает успешное сканирование и обратный вызов... э... вызывается! :) - person Dave Tyler; 25.05.2017