【求助】android安卓开发,问问大佬们

本人还是小白,最近在写一个app,需要和嵌入式端一直保持联系;有个功能是把程序传输到嵌入式端,需要每发送一段命令,就要求收到嵌入式端的回复,之后才能继续发送下一段命令,请问大佬们是怎么写的,或者有没有教程可以参考一下。

我现在写的程序没办法在接收到回复以后继续执行发送下一段命令,程序如下:

public class loadActivity extends AppCompatActivity {
    private MqttHelper mqttHelper;
    private Handler handler;
    private Button confirmButton;
    private Button cancleButton;
    private String account="0000";
    private String passwd="0000";
    private EditText editTextAccout;
    private EditText editTextPasswd;
    final String[] items4 = new String[]{"电机", "面板"};//弹窗item
    private int index=0;
    private static final int READ_REQUEST_CODE = 42;
    private Uri filePathUri=null; //下面用于存放回传的文件地址。
    private ScheduledExecutorService scheduler;
    private int num;//表示未响应时间
    private byte[] motorSend={0x10,0x02,0x40,0x00,0x00,0x42,0x10,0x03};
    private byte[] panelSend={0x10,0x02,0x41,0x00,0x00,0x43,0x10,0x03};
    private byte[] motorComplete={0x10,0x02,0x44,0x00,0x00,0x46,0x10,0x03};
    private byte[] panelComplete={0x10,0x02,0x45,0x00,0x00,0x47,0x10,0x03};
    private byte[] motorSendReceive={0x10,0x02,0x40,0x00,0x01,0x43,0x10,0x03};
    private byte[] PanelSendReceive={0x10,0x02,0x41,0x00,0x01,0x44,0x10,0x03};
    private byte[] motorCompleteReceive={0x10,0x02,0x44,0x00,0x01,0x47,0x10,0x03};
    private byte[] panelCompleteReceive={0x10,0x02,0x45,0x00,0x01,0x48,0x10,0x03};
    private byte[] motorUpdate={0x10,0x02,0x46,0x00,0x01,0x47,0x10,0x03};
    private byte[] panelUpdate={0x10,0x02,0x47,0x00,0x01,0x48,0x10,0x03};
    private boolean isMotor=false;//表示更新的是电机还是
    private int sector = 0; // 用于跟踪当前的sector值
    private boolean waitingForResponse = true; // 用于等待回应标志
    private byte bytes[];
    private ProgressDialog progressDialog;//进度条弹窗
    private AlertDialog alertDialog2;//更新对象对话框
    private AlertDialog alertDialog5;//返回弹窗
    private AlertDialog waitingDialog;//
    private boolean isWaitingForResponse;//回应是否超时

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.load);
        //取消按钮
        cancleButton = findViewById(R.id.button5);
        cancleButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                finish();
            }
        });

        editTextAccout = findViewById(R.id.editTextAccout);
        editTextPasswd = findViewById(R.id.editTextPasswd);

        //确认按钮
        confirmButton = findViewById(R.id.button6);
        confirmButton.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                switch(v.getId()){
                    case R.id.button6:
                        //getText() 返回的是一个 Editable 对象,而不是一个 String
                        String inputAccount = editTextAccout.getText().toString();
                        String inputPasswd = editTextPasswd.getText().toString();

                        if (inputAccount.equals(account) && inputPasswd.equals(passwd)) {
                            //申请sd读写权限
                            int permission_write = ContextCompat.checkSelfPermission(loadActivity.this,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE);
                            int permission_read = ContextCompat.checkSelfPermission(loadActivity.this,
                                    Manifest.permission.READ_EXTERNAL_STORAGE);
                            if (permission_write != PackageManager.PERMISSION_GRANTED
                                    || permission_read != PackageManager.PERMISSION_GRANTED) {
                                Toast.makeText(loadActivity.this, "正在请求权限", Toast.LENGTH_SHORT).show();
                                //申请权限,特征码自定义为1,可在回调时进行相关判断
                                ActivityCompat.requestPermissions(loadActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
                            }
                            pickFile();//选择文件
                            break;
                        }else{
                            Toast.makeText(loadActivity.this, "账号密码错误", Toast.LENGTH_SHORT).show();
                        }
                }

            }
        });

        handler = new Handler(Looper.myLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case 3:
                        byte[] receivedMessage;
                        try {
                            receivedMessage = ((String)msg.obj).getBytes("UTF-8");
                            parseByteobj(receivedMessage);
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 50:
                        // 更新进度
                        int progress = (int) msg.obj;
                        if (progressDialog != null && progressDialog.isShowing()) {
                            progressDialog.setProgress(progress);
                        }
                        break;
                    case 51:
                        // 传输完成,关闭进度对话框
                        if (progressDialog != null && progressDialog.isShowing()) {
                            progressDialog.dismiss();
                            if (waitingForResponse) {
                                Waiting();
                            }else{
                                // 如果不在等待响应,直接显示完成对话框
                                finishingDialog();
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
        };

        mqttHelper= ((MyApplication) getApplication()).getMqttHelper();
        mqttHelper.connect();
        mqttHelper.setHandler(handler);

    }

    //选择文件之后
    private ActivityResultLauncher<Intent> filePickerLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    Intent data = result.getData();
                    if (data != null) {
                        // 处理文件选择
                        filePathUri = data.getData();
                        // 显示对话框
                        showDialog();
                    }
                }
            }
    );

    // 启动文件选择
    private void pickFile() {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        filePickerLauncher.launch(intent);
    }

    // 更新对象对话框
    private void showDialog() {
        alertDialog2 = new AlertDialog.Builder(this)
                .setTitle("请选择更新对象")
                .setSingleChoiceItems(items4, 0, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        index = i;
                    }
                })
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        try {
                            bytes=readLocalFile(filePathUri);
                            waitingTransDialog();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        finish();
                    }
                })
                .create();
        alertDialog2.show();
    }

    // 进度条弹窗
    private void waitingTransDialog() {
        progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("程序更新中···");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setMax(100);
        progressDialog.setCancelable(false);
        progressDialog.show();

        // 开始文件传输
        if (index == 0) { //电机
            int unsignedValue = motorSend[2] & 0xFF; // 对应的无符号值为 128
            mqttHelper.publishMessage(mqttHelper.getPubTopic(), motorSend);
            // 等待回应
            waitingForResponse = true;
            num=0;
            if(setWaitingForResponse()) {
                unsignedValue = bytes[2] & 0xFF; // 对应的无符号值为 128
//            mqttHelper.publishMessageWithProgress(mqttHelper.getPubTopic(), bytes);
                sendBytesWithHeaderAndFooter(bytes);
                //接收到回复以后发送结束命令
                mqttHelper.publishMessage(mqttHelper.getPubTopic(), motorComplete);
            }
        } else { //面板
            int unsignedValue = panelSend[2] & 0xFF; // 对应的无符号值为 128
            mqttHelper.publishMessage(mqttHelper.getPubTopic(), panelSend);
            // 等待回应
            waitingForResponse = true;
            num=0;
//            if(setWaitingForResponse()) {
//                unsignedValue = bytes[2] & 0xFF; // 对应的无符号值为 128
////            mqttHelper.publishMessageWithProgress(mqttHelper.getPubTopic(), bytes);
//                sendBytesWithHeaderAndFooter(bytes);
//                mqttHelper.publishMessage(mqttHelper.getPubTopic(), panelComplete);
//            }
        }
    }



    // 发送 bytes 数组,并添加头部和尾部
    private void sendBytesWithHeaderAndFooter(byte[] bytes) {
        int segmentSize = 512 - 6; // 每段实际数据长度(减去头尾字节长度)
        int totalSegments = (int) Math.ceil((double) bytes.length / segmentSize);
        sector = 0; // 重置sector值
        sendNextSegment(bytes, segmentSize, totalSegments);
    }

    // 发送下一段数据
    private void sendNextSegment(byte[] bytes, int segmentSize, int totalSegments) {
        if (sector < totalSegments) {
            int start = sector * segmentSize;
            int end = Math.min(start + segmentSize, bytes.length);
            byte[] segment = createSegment(bytes, start, end);
            mqttHelper.publishMessageWithProgress(mqttHelper.getPubTopic(), segment);
            waitingForResponse = true; // 发送数据后等待回应
        } else {
            // 全部数据发送完成,发送完成信号
            if (index == 0) {
                mqttHelper.publishMessage(mqttHelper.getPubTopic(), motorComplete);
            } else {
                mqttHelper.publishMessage(mqttHelper.getPubTopic(), panelComplete);
            }
            handler.sendEmptyMessage(51); // 通知完成
        }
    }

    // 接收byte数组
    private void parseByteobj(byte[] byteobj) {
        int ints[] = new int[byteobj.length / 2];
        for (int i = 0; i < byteobj.length; ) {
            ints[i / 2] = byteobj[i] * 16 + byteobj[i + 1];
            i = i + 2;
        }
        if (ints.equals(motorCompleteReceive))
            waitingForResponse = false; // 收到回应
        else if (ints.equals(panelCompleteReceive))
            waitingForResponse = false; // 收到回应
        byte[] expectedResponse = getExpectedResponseForCurrentSector();
        if (Arrays.equals(byteobj, expectedResponse)) {
            waitingForResponse = false; // 收到回应
            num = 0; // 重置计数
            sector++; // 增加sector,准备发送下一段数据
            handler.post(() -> sendNextSegment(bytes, 512 - 6, (int) Math.ceil((double) bytes.length / (512 - 6))));
        } else {
            // 未收到预期回应,可以选择重发或记录日志等处理
        }

    }

    // 根据当前的sector值获取预期的回应
    private byte[] getExpectedResponseForCurrentSector() {
        byte[] response = new byte[8];
        response[0] = 0x10;
        response[1] = 0x02;
        response[2] = (index == 0) ? (byte) 0x42 : (byte) 0x43;
        response[3] = (byte) sector;
        response[4] = 0x01;
        response[5] = (byte) (0x45 + sector);
        response[6] = 0x10;
        response[7] = 0x03;
        return response;
    }


    // 检查是否收到回应
    private boolean setWaitingForResponse(){
        Handler checkResponseHandler = new Handler(Looper.getMainLooper());
        Runnable checkResponseRunnable = new Runnable() {
            @Override
            public void run() {
                if (waitingForResponse) {//未收到回应
                    num++;
                    Waiting();
                    if (num >= 5) {
                        Disconnect();
                        isWaitingForResponse=false;
                    } else {
                        isWaitingForResponse=true;
                        checkResponseHandler.postDelayed(this, 1000); // 1秒后再次检查
                    }
                }else{//收到了回应
                    isWaitingForResponse=true;
                }
            }
        };
        checkResponseHandler.postDelayed(checkResponseRunnable, 1000); // 1秒后开始检查
        return isWaitingForResponse;
    }

    // 创建包含头尾字节的 segment
    private byte[] createSegment(byte[] bytes, int start, int end) {
        // 创建新数组,包含头部、原始数据段和尾部
        byte[] segment = new byte[(end - start) + 6];

        // 设置头部 {0x10, 0x02, 0x42}
        segment[0] = 0x10;
        segment[1] = 0x02;

        if(index==0) segment[2] = 0x42;//电机
        else segment[2] = 0x43;//面板

        // 拷贝原始数据
        System.arraycopy(bytes, start, segment, 3, end - start);

        // 设置尾部 {sector, 0x10, 0x03}
        segment[segment.length - 3] = (byte) sector; // 设置 sector 值
        segment[segment.length - 2] = 0x10;
        segment[segment.length - 1] = 0x03;

        return segment;
    }

    private void Waiting() {
        waitingDialog = new AlertDialog.Builder(this)
                .setMessage("请等待···")
                .create();
        waitingDialog.show();
    }

    // 断开对话框
    private void Disconnect() {
        // 关闭等待中的弹窗
        if (waitingDialog != null && waitingDialog.isShowing()) {
            waitingDialog.dismiss();
        }
        AlertDialog alertDialog2 = new AlertDialog.Builder(this)
                .setTitle("与主机连接断开,请重新尝试")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Intent intent = new Intent(loadActivity.this, MainActivity.class);
                        startActivity(intent);
                    }
                })
                .create();
        alertDialog2.show();
    }

    // 显示返回对话框
    private void finishingDialog() {
        alertDialog5 = new AlertDialog.Builder(this)
                .setTitle("程序更新完毕,是否返回")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        Intent intent = new Intent(loadActivity.this, MainActivity.class);
                        startActivity(intent);
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        finish();
                    }
                })
                .create();
        alertDialog5.show();
    }

    private byte[] readLocalFile(Uri fileName) throws IOException {
        InputStream inputStream = getContentResolver().openInputStream(fileName);;
        byte[] data = toByteArray(inputStream);
        inputStream.close();
        return data;
    }

    private byte[] toByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[1024];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        buffer.flush();
        return buffer.toByteArray();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
        }
    }


}
2 个赞

android 小白,不懂,帮顶

1 个赞

不懂帮顶,我最近也在写一个app,Claude直接搞定,不过要警惕ai把代码越改越烂

1 个赞

From 软件开发 to 开发调优

从文字描述看,我觉得用mqtt是不是一个好的解决方案?

1 个赞

你就不能摘些重点吗?再不济把代码放在代码块里啊。。

// 等待回应
        waitingForResponse = true;
        num=0;
        if(setWaitingForResponse()) {}

这个,你的setWaitingForResponse()永远都是返回true,里面是个异步方法,不是同步的,导致调用setWaitingForResponse()都是返回你前面设置的值,可以传个CallBack 进去。但是你这个代码没多少拯救的必要。不如让AI 给你优化一下会比你自己写的质量高。

1 个赞

谢谢大佬,我去看一下回调函数

我用的就是mqtt进行通讯的捏