AsyncTask 仅在调试器中单步执行时执行
AsyncTask only executing when stepping through in debugger
首先,让我说我刚刚开始我的 Android 冒险,正在学习下面发布的代码。
所以我有一个 Zebra 条码扫描器和一个 Android 设备,它应该可以处理扫描的条码。这两个设备通过 BT 连接相互通信(我让它工作)。 JsonObjectRequest
正在处理扫描的条形码(也在工作)。根据外部服务的响应(或缺乏响应),扫描仪必须以某种方式做出反应:
green/red LED 亮起 - 蜂鸣器 - green/red LED 熄灭
这就是我挣扎的地方:
如果我只有蜂鸣器 - 一切正常。如果我有一个 LED on/off - 只有 LED 亮起。如果我有所有 3 个操作 - none 被执行。
现在,奇怪的是,调试器显示了接收和执行的那些操作
D/MainActivity: Barcode Received
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>45</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE7 0x04 0x00 0x04 0xFF 0x0C
I/BluetoothScanner: executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>17</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE6 0x04 0x00 0x11 0xFF 0x00
I/BluetoothScanner: soundBeeper command write successful. Wait for Status.
executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>46</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE8 0x04 0x00 0x04 0xFF 0x0B
executeCommand returningDCSSDK_RESULT_SUCCESS
我用来构建这些请求的代码基于 Zebra see here the Zebra Android SDK 提供的示例应用程序和文档,这就是我调用这些操作的方式:
private class MyAsyncTask extends AsyncTask<String,Integer,Boolean> {
int scannerId;
StringBuilder outXML;
DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode;
private CustomProgressDialog progressDialog;
public MyAsyncTask(int scannerId, DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode){
this.scannerId=scannerId;
this.opcode=opcode;
this.outXML = outXML;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new CustomProgressDialog(MainActivity.this, "Execute Command...");
progressDialog.show();
}
@Override
protected Boolean doInBackground(String... strings) {
return executeCommand(opcode,strings[0],null,scannerId);
}
@Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean executeCommand(DCSSDKDefs.DCSSDK_COMMAND_OPCODE opCode, String inXML, StringBuilder outXML, int scannerID) {
if (Application.sdkHandler != null)
{
if(outXML == null){
outXML = new StringBuilder();
}
DCSSDKDefs.DCSSDK_RESULT result=Application.sdkHandler.dcssdkExecuteCommandOpCodeInXMLForScanner(opCode,inXML,outXML,scannerID);
if(result== DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS)
return true;
else if(result==DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_FAILURE)
return false;
}
return false;
}
private final Handler dataHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case Constants.BARCODE_RECEIVED:
Barcode barcode = (Barcode) msg.obj;
sendApiHttpRequest(new String(barcode.getBarcodeData()));
break;
}
return false;
}
});
private void sendApiHttpRequest(String ticketId){
String url = "https://#################################/" + ticketId;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, myJsonListener(), myJsonErrorListener());
// tag the request for ease of debugging
jsonObjectRequest.setTag(TAG);
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}
private Response.Listener<JSONObject> myJsonListener() {
return new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
boolean status;
try {
status = response.getBoolean("status");
if (status){
setScanResultOK();
}else{
setScanResultERR();
}
}catch(JSONException e){
setScanResultERR();
Log.e(TAG, "Failure", e);
}
}
};
}
private Response.ErrorListener myJsonErrorListener() {
return new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
setScanResultERR();
Log.i(TAG, "Error : " + error.getLocalizedMessage());
}
};
}
private void setScanResultOK(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_ok);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_green);
}
private void setScanResultERR(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LOW_LONG_BEEP_3);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_err);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_red);
}
private void performOpcodeAction(String inXML) {
if (scannerID != -1) {
new MyAsyncTask(scannerID, DCSSDKDefs.DCSSDK_COMMAND_OPCODE.DCSSDK_SET_ACTION).execute(new String[]{inXML});
} else {
Toast.makeText(this, "Invalid scanner ID", Toast.LENGTH_SHORT).show();
}
}
private void prepareInXML(int value){
String inXML = "<inArgs><scannerID>" + scannerID + "</scannerID><cmdArgs><arg-int>" +
value + "</arg-int></cmdArgs></inArgs>";
performOpcodeAction(inXML);
}
当我设置断点并单步执行代码时,所有操作都会执行,一旦我 运行 应用程序,我就会遇到这些问题。
谁能帮帮我?
这是我从您的代码中了解到的内容。您正在向服务器发送 HTTP 请求,并根据响应执行一系列事件,例如 LED 和声音状态切换。
作为后台,Asynctask用于在后台线程上执行一段代码。在您的情况下,您想要执行这些命令。从名称上看,它们是异步的,并且将 运行 与您的主线程(至少是 doInBackground)并行。
在 setScanResultOK
和 setScanResultERR
中,您可能会实例化 3 个异步任务。默认情况下,只有其中一个会 运行,asynctasks 运行 在单个执行线程上。如果你想 运行 它们一起,在线程池执行器中执行它们。
现在,您提到要按顺序 运行 它们。我建议重构您的代码。
- 创建 2 个异步任务,1 个表示成功,1 个表示错误。
- 在 doInBackground
中执行多次 prepareInXML
调用
- 根据响应实例化一个asynctask,并执行。
举个例子:
@Override
protected Boolean doInBackground(String... strings) {
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON)) {
return false;
}
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP)) {
return false;
}
return prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
}
当然,这需要您更改一些函数签名来适应。然后处理 onPostExecute 中的所有 UI 变化。
@Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
/* perform UI changes particular to the type of task (success/fail) */
}
更新:
尝试在命令之间添加延迟。 no op 可能实际上是一个声音关闭序列,发生得非常快,我们会注意到。
首先,让我说我刚刚开始我的 Android 冒险,正在学习下面发布的代码。
所以我有一个 Zebra 条码扫描器和一个 Android 设备,它应该可以处理扫描的条码。这两个设备通过 BT 连接相互通信(我让它工作)。 JsonObjectRequest
正在处理扫描的条形码(也在工作)。根据外部服务的响应(或缺乏响应),扫描仪必须以某种方式做出反应:
green/red LED 亮起 - 蜂鸣器 - green/red LED 熄灭
这就是我挣扎的地方:
如果我只有蜂鸣器 - 一切正常。如果我有一个 LED on/off - 只有 LED 亮起。如果我有所有 3 个操作 - none 被执行。
现在,奇怪的是,调试器显示了接收和执行的那些操作
D/MainActivity: Barcode Received
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>45</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE7 0x04 0x00 0x04 0xFF 0x0C
I/BluetoothScanner: executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>17</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE6 0x04 0x00 0x11 0xFF 0x00
I/BluetoothScanner: soundBeeper command write successful. Wait for Status.
executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>46</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE8 0x04 0x00 0x04 0xFF 0x0B
executeCommand returningDCSSDK_RESULT_SUCCESS
我用来构建这些请求的代码基于 Zebra see here the Zebra Android SDK 提供的示例应用程序和文档,这就是我调用这些操作的方式:
private class MyAsyncTask extends AsyncTask<String,Integer,Boolean> {
int scannerId;
StringBuilder outXML;
DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode;
private CustomProgressDialog progressDialog;
public MyAsyncTask(int scannerId, DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode){
this.scannerId=scannerId;
this.opcode=opcode;
this.outXML = outXML;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new CustomProgressDialog(MainActivity.this, "Execute Command...");
progressDialog.show();
}
@Override
protected Boolean doInBackground(String... strings) {
return executeCommand(opcode,strings[0],null,scannerId);
}
@Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean executeCommand(DCSSDKDefs.DCSSDK_COMMAND_OPCODE opCode, String inXML, StringBuilder outXML, int scannerID) {
if (Application.sdkHandler != null)
{
if(outXML == null){
outXML = new StringBuilder();
}
DCSSDKDefs.DCSSDK_RESULT result=Application.sdkHandler.dcssdkExecuteCommandOpCodeInXMLForScanner(opCode,inXML,outXML,scannerID);
if(result== DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS)
return true;
else if(result==DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_FAILURE)
return false;
}
return false;
}
private final Handler dataHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case Constants.BARCODE_RECEIVED:
Barcode barcode = (Barcode) msg.obj;
sendApiHttpRequest(new String(barcode.getBarcodeData()));
break;
}
return false;
}
});
private void sendApiHttpRequest(String ticketId){
String url = "https://#################################/" + ticketId;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, myJsonListener(), myJsonErrorListener());
// tag the request for ease of debugging
jsonObjectRequest.setTag(TAG);
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}
private Response.Listener<JSONObject> myJsonListener() {
return new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
boolean status;
try {
status = response.getBoolean("status");
if (status){
setScanResultOK();
}else{
setScanResultERR();
}
}catch(JSONException e){
setScanResultERR();
Log.e(TAG, "Failure", e);
}
}
};
}
private Response.ErrorListener myJsonErrorListener() {
return new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
setScanResultERR();
Log.i(TAG, "Error : " + error.getLocalizedMessage());
}
};
}
private void setScanResultOK(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_ok);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_green);
}
private void setScanResultERR(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LOW_LONG_BEEP_3);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_err);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_red);
}
private void performOpcodeAction(String inXML) {
if (scannerID != -1) {
new MyAsyncTask(scannerID, DCSSDKDefs.DCSSDK_COMMAND_OPCODE.DCSSDK_SET_ACTION).execute(new String[]{inXML});
} else {
Toast.makeText(this, "Invalid scanner ID", Toast.LENGTH_SHORT).show();
}
}
private void prepareInXML(int value){
String inXML = "<inArgs><scannerID>" + scannerID + "</scannerID><cmdArgs><arg-int>" +
value + "</arg-int></cmdArgs></inArgs>";
performOpcodeAction(inXML);
}
当我设置断点并单步执行代码时,所有操作都会执行,一旦我 运行 应用程序,我就会遇到这些问题。
谁能帮帮我?
这是我从您的代码中了解到的内容。您正在向服务器发送 HTTP 请求,并根据响应执行一系列事件,例如 LED 和声音状态切换。
作为后台,Asynctask用于在后台线程上执行一段代码。在您的情况下,您想要执行这些命令。从名称上看,它们是异步的,并且将 运行 与您的主线程(至少是 doInBackground)并行。
在 setScanResultOK
和 setScanResultERR
中,您可能会实例化 3 个异步任务。默认情况下,只有其中一个会 运行,asynctasks 运行 在单个执行线程上。如果你想 运行 它们一起,在线程池执行器中执行它们。
现在,您提到要按顺序 运行 它们。我建议重构您的代码。
- 创建 2 个异步任务,1 个表示成功,1 个表示错误。
- 在 doInBackground 中执行多次
- 根据响应实例化一个asynctask,并执行。
prepareInXML
调用
举个例子:
@Override
protected Boolean doInBackground(String... strings) {
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON)) {
return false;
}
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP)) {
return false;
}
return prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
}
当然,这需要您更改一些函数签名来适应。然后处理 onPostExecute 中的所有 UI 变化。
@Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
/* perform UI changes particular to the type of task (success/fail) */
}
更新: 尝试在命令之间添加延迟。 no op 可能实际上是一个声音关闭序列,发生得非常快,我们会注意到。