Daniel Vlasenko Daniel Vlasenko - 5 months ago 9
Android Question

Declaration of field without initializations and usages in Java

I have a question which refers to java compiler behavior and also different APIs of android.

I have class representing Bluetooth LE connection. And I check version of API in this class to know which methods to scan for devices I must use. Here it is:

public class BleConnector{

private MyScanCallback _scanCallback;


private LeScanHandle _leScanHndl;
private BluetoothAdapter _bluetoothAdapter;

/**
* Initializes new instance of BLE connector
*/
public BleConnector()
{
//Creating handle for device scan callback;
_leScanHndl = new LeScanHandle();

//Check version of android api
//If it is bigger of equal to 21
//create scan callback for higher versions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
_scanCallback = new ScanCallback(_leScanHndl);
}
}


public void startScan(Context context) throws PermissoinException
{
final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
_bluetoothAdapter = bluetoothManager.getAdapter();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
_bluetoothAdapter.getBluetoothLeScanner().startScan(_scanCallback);
}
else
{
throw new PermissoinException("Location permission does not allowed");
}
}
else
{
_bluetoothAdapter.startLeScan(_leScanHndl);
}
//TODO notify
}

public void stopScan()
{
if (_bluetoothAdapter != null)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
_bluetoothAdapter.getBluetoothLeScanner().stopScan(_scanCallback);
} else
{
_bluetoothAdapter.stopLeScan(_leScanHndl);
}
}

//TODO notify
}

private void connectToDevice(BluetoothDevice device)
{
//TODO notify

//TODO connect gatt
}


Class MyScanCallback is marked with @TargetAPI 21 and of course I don't want to work with it if version of my device is less than 21

As you can see all usages and initialization of _scanCallback are inside if statements. So my question is:

Will I have any troubles with declaration
private MyScanCallback _scanCallback;
on devices with api<21 or compiler will remove it if there is no initialization and usages of _scanCallback?

Thank you!

UDT

Oh, i didn't say that MyScanCallback inherits ScanCallback wich is from 21 API level
public class MyScanCallback extends ScanCallback

Answer

@TargetApi 21 is just to prevent any compilation errors for any new APIs used. Byt to actually avoid the code to be executed, it must be wrapped around build version check as you have done at couple of places.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
}

So in this scenario, definitely a variable of MyScanCallback will be created but it will not be instantiated on devices with api<21 as you have wrapped it around version check in constructor.

As you mentioned that it is using ScanCallback that has been introduced in API 21, then definitely it will be an issue to use it in the older version.

To get rid of this, I would recommend to create an abstract class as below:

public abstract class BleConnector{

public abstract void startScan(Context context);

}

and then create two classes

public class BleConnectOldApi extends BleConnector{
public void startScan(Context context) throws PermissoinException {
//Your code here
}
}

and

@TargetApi(21)
public class BleConnect21Api extends BleConnector{

private MyScanCallback _scanCallback;

public void startScan(Context context) throws PermissoinException {
//Your code here
}
}

and finally have a factory class

public class BleConnectorFactory{

    public static BleConnector getBleConnector() {

        if (android.os.Build.VERSION.SDK_INT >= 21) {
            return new BleConnect21Api();
        }else{
            return new BleConnectOldApi();
        }

    }
}

This way you can prevent unwanted error for using a class that do not exists in older API version.

Hope that helps you out.