2015-12-10 16 views
5

私は私のコードで私はBLEのためのAPIから実装された新しいスキャンとScanCallbackを使用したい、BLEデバイスと接続する必要がアプリを開発しています21(Android 5)でも、Android 4.3以降との互換性を維持する必要があります。のAndroidのBluetooth低エネルギーコード> = 21 AND API <21

 if (Build.VERSION.SDK_INT >= 21) { 
      mLEScanner.startScan(filters, settings, mScanCallback); 
     } else { 
      btAdapter.startLeScan(leScanCallback); 
     } 

をそして、私は20に2つのコールバック、API 21用と、上記とAPI 18のための1つを定義しています:

だから私は、このように、例えば、コードを書いた

//API 21 
private ScanCallback mScanCallback = new ScanCallback() { 
     @Override 
     public void onScanResult(int callbackType, ScanResult result) { 
       BluetoothDevice btDevice = result.getDevice(); 
       connectToDevice(btDevice); 
     } 
     public void connectToDevice(BluetoothDevice device) { 
       if (mGatt == null) { 
        mGatt = device.connectGatt(context, false, btleGattCallback); 
        if (Build.VERSION.SDK_INT < 21) { 
         btAdapter.stopLeScan(leScanCallback); 
        } else { 
         mLEScanner.stopScan(mScanCallback); 
        } 
       } 
     } 
    }; 


//API 18 to 20 
     private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { 
     @Override 
     public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { 

     btAdapter.stopLeScan(leScanCallback); 
     runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 
       mBluetoothGatt = device.connectGatt(context, false, btleGattCallback); 
      } 
     }); 


    } 
}; 

私はまた、注釈

@TargetApi(21) 

を追加しましたが、私は、Android 4.xの上でアプリケーションを起動したとき、それはすぐに報告クラッシュクラスScanCallbackが見つからないというエラー(Android 5以上でのみ使用されることを意図したもの)

どうすればこの問題を解決できますか?

ありがとうございました。 Daniele。

+0

完全なスタックトレースを表示できますか? –

答えて

0

匿名の内部クラスを作成しているため、コードがクラッシュしています。そのため、実行時にsCanCallbackクラスが見つかりません。

以下の方法で試してみて、結果を共有してください。これを試す前に、コールバックにコメントを付けてください(ScanCallback)。

if (Build.VERSION.SDK_INT >= 21) { 
      mLEScanner.startScan(filters, settings, new ScanCallback() { 
     @Override 
     public void onScanResult(int callbackType, ScanResult result) { 
       BluetoothDevice btDevice = result.getDevice(); 
       connectToDevice(btDevice); 
     } 
     public void connectToDevice(BluetoothDevice device) { 
       if (mGatt == null) { 
        mGatt = device.connectGatt(context, false, btleGattCallback); 
        if (Build.VERSION.SDK_INT < 21) { 
         btAdapter.stopLeScan(leScanCallback); 
        } else { 
         mLEScanner.stopScan(mScanCallback); 
        } 
       } 
     } 
    }; 
     } else { 
      btAdapter.startLeScan(leScanCallback); 
     } 
3
  1. AbstractBluetoothLeクラスとIBleScanCallbackインターフェースを作成します。 IBleScanCallbackインターフェイスはマーカーインターフェイスです。別の言い方では、メソッドを持たないインターフェースです。また、必要に応じてインタフェースにメソッドを追加することもできます。これらの方法は、clearListOfFoundBleDevices()等
  2. BluetootLeLollipopを作成し、AbstractBluetoothLeクラスを拡張BluetoothLeJellyBeanクラス、scanCallbacks即ちgetListOfFoundBleDevicesのすべてのタイプ()のために同じ機能を行います。 BluetootLeLollipopクラスを拡張するBluetootLeMarshmallowクラスも作成します。 AbstractBluetoothLeクラスはフィールドmIBleScanCallbackを保護しています。これはIBleScanCallbackオブジェクトです。
  3. IBleScanCallbackを実装するBleScanCallbackBaseクラスを作成します。
  4. ScanCallbackクラスを拡張し、IBleScanCallbackインタフェースを実装LollipopScanCallbackクラスを作成します。 。このクラスには保護フィールドscanCallbackがあり、BleScanCallbackBaseオブジェクトとしてインスタンス化されます。 LollipopScanCallbackクラスを拡張するMarshmallowScanCallbackクラスも作成してください。 onScanCallback(...)
  5. LollipoScanCallbackオーバーライドonScanResult(int callbackType, ScanResult result)このメソッド内メソッドscanCallbackオブジェクトのonScanCallback(...)呼び出し:
  6. BleScanCallbackBaseを拡張しBleScanCallbackBaseオーバーライド方法でBluetoothAdapter.LeScanCallback
  7. を実装JellyBeanScanCallbackクラスを作成します。JellyBeanScanCallbackオーバーライドonLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord)で、このメソッドの呼び出し最後にonScanCallback(...)
  8. 内部
  9. 、デバイスはBleScanCallbackBaseクラスのonScanCallback(...)方法で発見されたときに実行する必要があるものは何でも。

つまり、継承を超えて構成について読むことができます。これはあなたの質問に対する答えではありませんが、これは最終的に達成したいことのきちんとした方法です。クラス図は次のとおりです。enter image description here

+0

'ScanCallback'を拡張するには、APIの最小値は21でなければなりません。これは、Jellybeanよりも低いすべてのデバイスを除外することを意味します。 Android Studioのグ​​ラデーションビルドを変更して、デバイスに対応している場合はAPIレベル21以上の機能を使用することはできますか? – 0x6

+0

@ 0x6はい、あなたは正しいです。それに応じて私の答えを更新しました。再度確認してください。 – ulusoyca

+0

質問に答えるか、返信しないでください。 – GraSim

4

私は以下のことをしました。念のため、ここでのAndroidのドキュメントを約BluetoothLe

まず

二つの方法1 scanLeDevice21scanLeDevice18を作成しています。

は注釈付き要素のみ与えられたAPIレベル以上に呼ばれるべきであることを示します:scanLeDevice21に言う注釈@RequiresApi(21)を追加します。 これは、古い@TargetApiアノテーションと目的が似ていますが、minSdkVersionを超えるメソッド内の警告を「抑制」するのではなく、呼び出し元の要件であることをより明確に表しています。

セカンド

各メソッドを実装し、ここに私のコードです。

@RequiresApi(21) 
private void scanLeDevice21(final boolean enable) { 

    ScanCallback mLeScanCallback = new ScanCallback() { 

     @Override 
     public void onScanResult(int callbackType, ScanResult result) { 

      super.onScanResult(callbackType, result); 

      BluetoothDevice bluetoothDevice = result.getDevice(); 

      if (!bluetoothDeviceList.contains(bluetoothDevice)) { 
       Log.d("DEVICE", bluetoothDevice.getName() + "[" + bluetoothDevice.getAddress() + "]"); 
       bluetoothDeviceArrayAdapter.add(bluetoothDevice); 
       bluetoothDeviceArrayAdapter.notifyDataSetChanged(); 
      } 
     } 

     @Override 
     public void onBatchScanResults(List<ScanResult> results) { 
      super.onBatchScanResults(results); 

     } 

     @Override 
     public void onScanFailed(int errorCode) { 
      super.onScanFailed(errorCode); 
     } 
    }; 

    final BluetoothLeScanner bluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); 

    if (enable) { 
     // Stops scanning after a pre-defined scan period. 
     mHandler.postDelayed(() -> { 
      mScanning = false; 
      swipeRefreshLayout.setRefreshing(false); 
      bluetoothLeScanner.stopScan(mLeScanCallback); 
     }, SCAN_PERIOD); 

     mScanning = true; 
     bluetoothLeScanner.startScan(mLeScanCallback); 
    } else { 
     mScanning = false; 
     bluetoothLeScanner.stopScan(mLeScanCallback); 
    } 
} 


/** 
* Scan BLE devices on Android API 18 to 20 
* 
* @param enable Enable scan 
*/ 
private void scanLeDevice18(boolean enable) { 

    BluetoothAdapter.LeScanCallback mLeScanCallback = 
      new BluetoothAdapter.LeScanCallback() { 
       @Override 
       public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, 
            byte[] scanRecord) { 
        getActivity().runOnUiThread(new Runnable() { 
         @Override 
         public void run() { 
          bluetoothDeviceArrayAdapter.add(bluetoothDevice); 
          bluetoothDeviceArrayAdapter.notifyDataSetChanged(); 
         } 
        }); 
       } 
      }; 
    if (enable) { 
     // Stops scanning after a pre-defined scan period. 
     mHandler.postDelayed(() -> { 
      mScanning = false; 
      mBluetoothAdapter.stopLeScan(mLeScanCallback); 
     }, SCAN_PERIOD); 

     mScanning = true; 
     mBluetoothAdapter.startLeScan(mLeScanCallback); 
    } else { 
     mScanning = false; 
     mBluetoothAdapter.stopLeScan(mLeScanCallback); 
    } 

} 

サード

あなたはあなたがどのバージョンを尋ねるあなたのコードを囲むのデバイスをスキャンする必要があるたびに。たとえば、デバイスのリストを表示するにはRefreshLayoutがあります。結果は次のとおりです。

/** 
* Refresh listener 
*/ 
private void refreshScan() { 
    if (!hasFineLocationPermissions()) { 
     swipeRefreshLayout.setRefreshing(false); 


     //Up to marshmallow you need location permissions to scan bluetooth devices, this method is not here since is up to you to implement it and it is out of scope of this question. 
     requestFineLocationPermission(); 

    } else { 
     swipeRefreshLayout.setRefreshing(true); 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
      scanLeDevice21(true); 
     } else { 
      scanLeDevice18(true); 
     } 
    } 
} 

これだけです。

あなたは本当にulusのような答えを必要としないクラスをサブクラス化することは忘れてしまいます。

+1

ありがとう、偉大な仕事をして実装するのは本当に簡単です – winne2

+0

@ペドロこのソリューションを置くあなたの努力に感謝します。それは私のために働いた。 – Prashant

関連する問題