我正在启动一些后台服务,由于Web服务调用等原因,这些服务需要一些时间来配置...
但是我通过AsyncTask启动这些服务,以避免锁定主线程和GUI,但是GUI仍然被锁定。
我正在使用AsyncTask调用我的Activity onCreate()中的启动BluetoothService:
我只包含了相关的代码行:
//asynchronously - start the bluetooth service
new BluetoothServiceStart().execute();
然后在BluetoothServiceStart服务类中,Im使用Callable&Future任务从Web服务获取字节:
@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
我遇到了ANR,后来又崩溃了。
Android线程转储:
“ main @ 4817” prio = 5 tid = 0x2 nid = NA等待 java.lang.Thread.State:正在等待 阻止main @ 4817 在java.lang.Object.wait(Object.java:-1) 在java.lang.Thread.parkFor $(Thread.java:2135) -锁定<0x1a72>(一个java.lang.Object) 在sun.misc.Unsafe.park(Unsafe.java:358) 在java.util.concurrent.locks.LockSupport.park(LockSupport.java:190) 在java.util.concurrent.FutureTask.awaitDone(FutureTask.java:450) 在java.util.concurrent.FutureTask.get(FutureTask.java:192) 在ngfr.wams.controller.core.services.RuleEngineService.loadRules(RuleEngineService.java:358) 在ngfr.wams.controller.core.services.RuleEngineService.updateRules(RuleEngineService.java:462) 在ngfr.wams.controller.core.services.RuleEngineService.onCreate(RuleEngineService.java:131) 在android.app.ActivityThread.handleCreateService(ActivityThread.java:3542) 在android.app.ActivityThread.-wrap4(ActivityThread.java:-1) 在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1786) 在android.os.Handler.dispatchMessage(Handler.java:105) 在android.os.Looper.loop(Looper.java:164) 在android.app.ActivityThread.main(ActivityThread.java:6938) 在java.lang.reflect.Method.invoke(Method.java:-1) 在com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:327) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
错误行指向future.get()
。
我了解到future.get()
块是一种预期的行为,目的是为了等待Web服务返回字节,否则在网络连接/带宽较低的情况下,代码将继续执行并错过网络响应和数据。
future.get()
阻止了该服务,但是由于BluetoothService是使用BluetoothServiceStart AsyncTask启动的,所以为什么UI被阻止了??
谢谢
答案 0 :(得分:0)
一个普遍的错误假设是,服务正在启动活动之外的另一个线程上运行。它将在主线程上运行,如下所示:Services
警告:服务在其托管过程的主线程中运行;除非另行指定,否则该服务不会创建自己的线程,也不会在单独的进程中运行。如果您的服务要执行任何占用大量CPU的工作或阻止操作(例如MP3播放或联网),则应在服务内创建一个新线程以完成该工作。通过使用单独的线程,可以降低应用程序无响应(ANR)错误的风险,并且应用程序的主线程可以保持专用于用户与活动的交互。
startService
调用不会更改此行为,即使您在AsyncTask
中调用它也是如此。因此,如果要重新激活应用程序,则应在服务内部创建一个线程,该线程不会阻止该服务,因此也不会阻止主线程。
请注意,IntentServices
将任务卸载到工作线程中,但是在没有其他工作要做时会自动停止。
客户端通过Context.startService(Intent)调用发送请求;该服务将根据需要启动,使用工作线程依次处理每个Intent,并在工作耗尽时自行停止。
也许这不是您想要的蓝牙服务。
答案 1 :(得分:0)
生命周期方法始终在man应用程序循环上运行,因为系统会为您创建Service对象。因此,它的onStartCommand不会在您想要的后台线程上运行。如果您希望服务在后台线程上运行,请使用IntentService。