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)并行。

setScanResultOKsetScanResultERR 中,您可能会实例化 3 个异步任务。默认情况下,只有其中一个会 运行,asynctasks 运行 在单个执行线程上。如果你想 运行 它们一起,在线程池执行器中执行它们。

现在,您提到要按顺序 运行 它们。我建议重构您的代码。

  1. 创建 2 个异步任务,1 个表示成功,1 个表示错误。
  2. 在 doInBackground
  3. 中执行多次 prepareInXML 调用
  4. 根据响应实例化一个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 可能实际上是一个声音关闭序列,发生得非常快,我们会注意到。