I'm a beginner in Android Studio. I've recently picked up some Demo Apps for managing BLE devices, made them work separately, and am now trying to join two of them in a single App. Both Apps used a BLE Service, so I have to join them into a single service (or have them work together). While looking at the code I noticed that one of these Service classes has no onCreate() method. Then I looked into the implementation and found the Service is Instantiated using a nested class of the Service that extends the Binder class.
Here's the relevant code from the service class:
@SuppressLint("NewApi")
public class BluetoothLeService extends Service {
private final String TAG = BluetoothLeService.class.getSimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private BluetoothGattCharacteristic mNotifyCharacteristic;
private static EncryptDecode encryptDecode = new EncryptDecode(); // Encryption and Decryption tool task
private IBleOperateCallback mBleOperateCallback;
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE, SmctConstant.VALUE_BLE_CONNECTED);
Log.i(TAG, "Connected to GATT server.");
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE, SmctConstant.VALUE_BLE_DISCONNECTED);
close();
Log.i(TAG, "Disconnected from GATT server.");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
mBleOperateCallback.bleData(SmctConstant.KEY_BLE_CONNECT_STATE,
SmctConstant.VALUE_BLE_SERVICE_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
};
public class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private final IBinder mBinder = new LocalBinder();
/**
* Initializes a reference to the local Bluetooth adapter.
*
* @return Return true if the initialization is successful.
*/
public boolean initialize() {
// For API level 18 and above, get a reference to BluetoothAdapter
// through
// BluetoothManager.
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Log.e(TAG, "Unable to initialize BluetoothManager.");
return false;
}
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Log.e(TAG, "Unable to obtain a BluetoothAdapter.");
return false;
}
return true;
}
...
SOME MORE FUNCTIONS...
...
}
And this is how the Service instance gets declared in the Activity that uses it:
BluetoothLeService mBluetoothLeService;
mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
I am trying to understand: how exactly is the Class instantiated without the onCreate() method? I've checked the onCreate() method from the Service class and it just throws and exception. I need to understand it because the other service I'm using does have such method and I want to join them. Also: What is the difference between using this LocalBinder nested class and straight up using a class constructor?
EDIT: Here's the onCreate() method from the extended class Service. You can see it just throws a Runtime Exception. onStart() is identical.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package android.app;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.IBinder;
import java.io.FileDescriptor;
import java.io.PrintWriter;
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
public static final int START_CONTINUATION_MASK = 15;
public static final int START_FLAG_REDELIVERY = 1;
public static final int START_FLAG_RETRY = 2;
public static final int START_NOT_STICKY = 2;
public static final int START_REDELIVER_INTENT = 3;
public static final int START_STICKY = 1;
public static final int START_STICKY_COMPATIBILITY = 0;
public static final int STOP_FOREGROUND_DETACH = 2;
public static final int STOP_FOREGROUND_REMOVE = 1;
public Service() {
super((Context)null);
throw new RuntimeException("Stub!");
}
public final Application getApplication() {
throw new RuntimeException("Stub!");
}
public void onCreate() {
throw new RuntimeException("Stub!");
}
/** @deprecated */
@Deprecated
public void onStart(Intent intent, int startId) {
throw new RuntimeException("Stub!");
}
public int onStartCommand(Intent intent, int flags, int startId) {
throw new RuntimeException("Stub!");
}
public void onDestroy() {
throw new RuntimeException("Stub!");
}
public void onConfigurationChanged(Configuration newConfig) {
throw new RuntimeException("Stub!");
}
public void onLowMemory() {
throw new RuntimeException("Stub!");
}
public void onTrimMemory(int level) {
throw new RuntimeException("Stub!");
}
public abstract IBinder onBind(Intent var1);
public boolean onUnbind(Intent intent) {
throw new RuntimeException("Stub!");
}
public void onRebind(Intent intent) {
throw new RuntimeException("Stub!");
}
public void onTaskRemoved(Intent rootIntent) {
throw new RuntimeException("Stub!");
}
public final void stopSelf() {
throw new RuntimeException("Stub!");
}
public final void stopSelf(int startId) {
throw new RuntimeException("Stub!");
}
public final boolean stopSelfResult(int startId) {
throw new RuntimeException("Stub!");
}
public final void startForeground(int id, Notification notification) {
throw new RuntimeException("Stub!");
}
public final void stopForeground(boolean removeNotification) {
throw new RuntimeException("Stub!");
}
public final void stopForeground(int flags) {
throw new RuntimeException("Stub!");
}
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
throw new RuntimeException("Stub!");
}
}
EDIT2: As Gabe pointed out in his answer: This is just the stub code from the Service, not the actual implementation. So I got confused by the onCreate() method that Android Studio showed me.
There's a default implementation of onCreate in the Service class. If you don't override it, you just use that default implementation. That's sufficient to create the Service correctly, if you don't need additional logic.
Your other question should be asked separately (1 question per post), but there's not enough code for me to answer it- I have no idea what the variable service is. However, you never create a service via constructor- it will not be initialized properly. You always call startService or bindService and let Android create it.