Im starting several background services that take a while to configure due to web services calls, etc...
However Im starting these services via AsyncTask in order to avoid locking the main thread & GUI, however the GUI stills becomes locked.
Im using AsyncTask to call start a BluetoothService in my Activity onCreate():
I only included relevant lines of code:
//asynchronously - start the bluetooth service
new BluetoothServiceStart().execute();
Then in the BluetoothServiceStart service class, Im using Callable & Future task to get bytes from a web service:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// stop the service when the notification bar is pressed
if (intent != null && ACTION_STOP_SERVICE.equals(intent.getAction())) {
Log.d(TAG, "Stopping bluetooth service...");
broadcastServiceState(false);
stopSelf();
return START_NOT_STICKY;
}
// in case of attempting to restart while already running
clearSubscriptions();
Util.logToast(this, TAG, "Bluetooth service starting", Toast.LENGTH_SHORT, Util.DEBUG);
setupNotification();
// find and load JSON config file
loadDevices();
}
/**
* Gets the UUIDs of devices to connect to from the bluetooth JSON file.
*/
private void loadDevices() {
devicesLoaded = false;
Byte [] bytesFromWebService = null;
InputStream is = null;
URL url = null;
try {
if (ConnectivityMonitoring.hasNetwork()) {
//lets get the path of rest service that has the config file
String address = NgfrApp.getContext().getResources().getString(R.string.address);
String configuration_restful_port = NgfrApp.getContext().getResources().getString(R.string.rest_port);
String client_name = NgfrApp.getContext().getResources().getString(R.string.client_name);
String protocol = NgfrApp.getContext().getResources().getString(R.string.protocol);
//construct bluetooth config path
String bluetooth_config_path = NgfrApp.getContext().getResources().getString(R.string.bluetooth_path);
url = new URL(protocol + "://" + address + ":" + configuration_restful_port + bluetooth_config_path + client_name);
//lets execute an FutureTask (async task with a result, that blocks until result is returned).
ExecutorService exService = Executors.newSingleThreadExecutor();
Log.i(TAG, "making call to URL:" + url.toString());
Future<byte []> future = exService.submit(new CallWebServiceAndGetBytes(url));
bytesFromWebService = Util.toObjects(future.get());
}
if (bytesFromWebService != null) {
devices = readDeviceConfigFromWebService(bytesFromWebService);
Log.i(TAG, "Loaded configuration from URL:" + url.toString());
} else {
// read in the device UUIDs from the file
is = Util.scanForJson(getString(R.string.file_path), getString(R.string.bt_config_file));
devices = Util.readJsonStream(is, localConfigReadFunc);
Log.i(TAG, "Read config file from PATH:" + getString(R.string.file_path)+getString(R.string.bt_config_file));
}
if (devices != null) {
if (devices.size() < 1)
Log.w(TAG, "No devices to load!");
devicesLoaded = true;
}
// devices successfully loaded
if (devices != null && devicesLoaded) {
Log.d(TAG, "" + devices.size() + " BLE device IDs retrieved");
Log.d(TAG, "Devices: " + devices.toString());
}
// failed to load devices or find the JSON file
else {
Log.e(TAG, "Unable to load devices! Creating empty list...");
devices = new ArrayList<>();
}
}
catch (MalformedURLException e1) {
e1.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
catch (FileNotFoundException e) {
Log.d(TAG, "Unable to locate bluetooth config file: " + getString(R.string.bt_config_file));
} catch (IOException e) {
Log.d(TAG, "Error reading json file: " + e.getMessage());
}
}//end loadDevices
Im getting an ANR & later crash.
Android Thread dump:
"main@4817" prio=5 tid=0x2 nid=NA waiting java.lang.Thread.State: WAITING blocks main@4817 at java.lang.Object.wait(Object.java:-1) at java.lang.Thread.parkFor$(Thread.java:2135) - locked <0x1a72> (a java.lang.Object) at sun.misc.Unsafe.park(Unsafe.java:358) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190) at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:450) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at ngfr.wams.controller.core.services.RuleEngineService.loadRules(RuleEngineService.java:358) at ngfr.wams.controller.core.services.RuleEngineService.updateRules(RuleEngineService.java:462) at ngfr.wams.controller.core.services.RuleEngineService.onCreate(RuleEngineService.java:131) at android.app.ActivityThread.handleCreateService(ActivityThread.java:3542) at android.app.ActivityThread.-wrap4(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1786) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6938) at java.lang.reflect.Method.invoke(Method.java:-1) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
The error line points to future.get()
.
I understand that the future.get()
blocks, which is intended behavior in order to wait for the web service to return the bytes otherwise in low network connectivity/bandwidth situations the code will continue to execute and miss the network response & data.
The future.get()
blocks the Service, however since the BluetoothService is started using BluetoothServiceStart AsyncTask, then why is the UI blocked???
Thanks