android - 如何通过蓝牙获取 InputStream 并放入 Textview?

标签 android bluetooth textview inputstream

这是我在 SO 中的第一个问题。我是 Android 编程的新手(并且很兴奋),这是我的问题:我正在使用我的 Android 手机和微 Controller 构建一个项目。微 Controller 有一个距离传感器并传输它的值。我已经设法连接到微 Controller 并发送正确的信号,但我无法获得距离测量值或其他任何信息。该应用程序不会崩溃或不会从微 Controller 获取数据的任何事情(我的计算机从微 Controller 获取数据(数据是一个字符串))。我的 android 应用程序代码是这样的:

公共(public)类加速度计扩展 Activity {

// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int RECIEVE_MESSAGE = 3;

// Program variables
private byte microcOut;
private boolean ledStat;
private boolean connectStat = false;
private Button btnled;
private Button connect_button;
private TextView yAccel, xAccel, incoming;
protected static final int MOVE_TIME = 80;
private long lastWrite = 0;
OnClickListener myClickListener;
ProgressDialog myProgressDialog;
private Toast failToast;
private Handler mHandler,h;
private StringBuilder sb = new StringBuilder();

// Sensor object used to handle accelerometer
private SensorManager mySensorManager; 
private List<Sensor> sensors; 
private Sensor accSensor;

// Bluetooth Stuff
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null; 
private OutputStream outStream = null;
private InputStream inStream = null;
private ConnectThread mConnectThread = null;
private ConnectedThread mConnectedThread;

private String deviceAddress = null;
// Well known SPP UUID (will *probably* map to RFCOMM channel 1 (default) if not in use); 
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

//Sound Clip to make app prettier
MediaPlayer myclip;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_accelerometer);
    myclip = MediaPlayer.create(this, R.raw.cartcar);
    myclip.start();
     // Finds buttons in .xml layout file
    btnled = (Button) findViewById(R.id.led_button1);
    connect_button = (Button) findViewById(R.id.connect_button1);
    yAccel = (TextView) findViewById(R.id.accText1);
    xAccel = (TextView) findViewById(R.id.accText2);
    incoming = (TextView) findViewById(R.id.incoming);
    // Set Sensor
    mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE); 
    sensors = mySensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if(sensors.size() > 0) accSensor = sensors.get(0);

    myProgressDialog = new ProgressDialog(this);
    failToast = Toast.makeText(this, R.string.failedToConnect, Toast.LENGTH_SHORT);
    mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
         if (myProgressDialog.isShowing()) {
                myProgressDialog.dismiss();
            }

         // Check if bluetooth connection was made to selected device
            if (msg.what == 1) {
                // Set button to display current status
                connectStat = true;
                connect_button.setText(R.string.connected);

                // Reset the BluCar
                microcOut = 0;
                ledStat = false;
                write(microcOut);
            }else {
                // Connection failed
             failToast.show();
            }
        }
    };


    h = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case RECIEVE_MESSAGE:                                                   // if receive massage
                byte[] readBuf = (byte[]) msg.obj;
                String strIncom = new String(readBuf, 0, msg.arg1);                 // create string from bytes array
                sb.append(strIncom);                                                // append string
                int endOfLineIndex = sb.indexOf("\r\n");                            // determine the end-of-line
                if (endOfLineIndex > 0) {                                            // if end-of-line,
                    String sbprint = sb.substring(0, endOfLineIndex);               // extract string
                    sb.delete(0, sb.length());                                      // and clear
                    incoming.setText("Data from Arduino: " + sbprint);            // update TextView 
                }
                //Log.d(TAG, "...String:"+ sb.toString() +  "Byte:" + msg.arg1 + "...");
                break;
            }
        };
    };
 // Check whether bluetooth adapter exists
    btAdapter = BluetoothAdapter.getDefaultAdapter(); 
    if (btAdapter == null) { 
         Toast.makeText(this, R.string.no_bt_device, Toast.LENGTH_LONG).show(); 
         finish(); 
         return; 
    } 

    // If BT is not on, request that it be enabled.
    if (!btAdapter.isEnabled()) {
        Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
    }
    /**********************************************************************
     * Buttons for controlling BluCar
     */
    connect_button.setOnClickListener(new View.OnClickListener() {

        // Connect to Bluetooth Module
        @Override
        public void onClick(View v) {
            if (connectStat) {
                // Attempt to disconnect from the device
                disconnect();
            }else{
                // Attempt to connect to the device
                connect();
            }
        }
    });

    // Toggle Headlights
    btnled.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (ledStat) {
                microcOut = (byte) (microcOut & 124);
                btnled.setText(R.string.ledbuttonON);
                ledStat = false;
            }else{
                microcOut = (byte) (microcOut | 128);
                btnled.setText(R.string.ledbuttonOFF);
                ledStat = true;
            }
            write(microcOut);
        }
    });

}
/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;

    ConnectThread(String MACaddress) {
        address = MACaddress;
        connectionStatus = true;
}

    public void run() {
    // When this returns, it will 'know' about the server, 
       // via it's MAC address. 
        try {
            BluetoothDevice device = btAdapter.getRemoteDevice(address);

            // We need two things before we can successfully connect 
            // (authentication issues aside): a MAC address, which we 
            // already have, and an RFCOMM channel. 
            // Because RFCOMM channels (aka ports) are limited in 
            // number, Android doesn't allow you to use them directly; 
            // instead you request a RFCOMM mapping based on a service 
            // ID. In our case, we will use the well-known SPP Service 
            // ID. This ID is in UUID (GUID to you Microsofties) 
            // format. Given the UUID, Android will handle the 
            // mapping for you. Generally, this will return RFCOMM 1, 
            // but not always; it depends what other BlueTooth services 
            // are in use on your Android device. 
            try { 
                 btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID); 
            } catch (IOException e) { 
                connectionStatus = false;
            } 
        }catch (IllegalArgumentException e) {
            connectionStatus = false;
        }

       // Discovery may be going on, e.g., if you're running a 
       // 'scan for devices' search from your handset's Bluetooth 
       // settings, so we call cancelDiscovery(). It doesn't hurt 
       // to call it, but it might hurt not to... discovery is a 
       // heavyweight process; you don't want it in progress when 
       // a connection attempt is made. 
       btAdapter.cancelDiscovery(); 

       // Blocking connect, for a simple client nothing else can 
       // happen until a successful connection is made, so we 
       // don't care if it blocks. 
       try {
            btSocket.connect(); 
       } catch (IOException e1) {
            try {
                 btSocket.close(); 
            } catch (IOException e2) {
            }
       }

       // Create a data stream so we can talk to server. 
       try { 
        outStream = btSocket.getOutputStream(); 
       } catch (IOException e2) {
        connectionStatus = false;
       }

       // Send final result
       if (connectionStatus) {
        mHandler.sendEmptyMessage(1);
       }else {
        mHandler.sendEmptyMessage(0);
       }
    }
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
     switch (requestCode) {
       case REQUEST_CONNECT_DEVICE:
         // When DeviceListActivity returns with a device to connect
           if (resultCode == Activity.RESULT_OK) {
            // Show please wait dialog
            myProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.pleaseWait), getResources().getString(R.string.makingConnectionString), true);

            // Get the device MAC address
            deviceAddress = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);
            // Connect to device with specified MAC address
              mConnectThread = new ConnectThread(deviceAddress);
              mConnectThread.start();

           }else {
             // Failure retrieving MAC address
             Toast.makeText(this, R.string.macFailed, Toast.LENGTH_SHORT).show();
           }
           break;
       case REQUEST_ENABLE_BT:
           // When the request to enable Bluetooth returns
           if (resultCode == Activity.RESULT_OK) {
               // Bluetooth is now enabled
           } else {
               // User did not enable Bluetooth or an error occured
               Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
               finish();
           }
        }
   }

public void write(byte data) {
     if (outStream != null) {
          try {
             outStream.write(data);
          } catch (IOException e) {
          }
      }
  }

  public void emptyOutStream() {
     if (outStream != null) {
          try {
             outStream.flush();
          } catch (IOException e) {
          }
      }
  }

  public void connect() {
     // Launch the DeviceListActivity to see devices and do scan
      Intent serverIntent = new Intent(this, DeviceList.class);
      startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
  }

  public void disconnect() {
     if (outStream != null) {
         try {
                outStream.close();
                connectStat = false;
                connect_button.setText(R.string.disconnected);
            } catch (IOException e) {
            }
     } 
  }
  private final SensorEventListener mSensorListener = new SensorEventListener() {

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {}

        @Override
        public void onSensorChanged(SensorEvent event) {
            // Checks whether to send steering command or not
            long date = System.currentTimeMillis();
            if (date - lastWrite > MOVE_TIME) {
                yAccel.setText(" " + event.values[1]);
                xAccel.setText(" " + event.values[0]);
                if (event.values[1] > 2.5) {
                    // Turn right
                    microcOut = (byte) (microcOut & 248);
                    microcOut = (byte) (microcOut | 4);
                }else if (event.values[1] < -2.5) {
                    // Turn left
                    microcOut = (byte) (microcOut & 244);
                    microcOut = (byte) (microcOut | 8);
                }else {
                    // Center the steering servo
                    microcOut = (byte) (microcOut & 240);
                }
                write(microcOut);
                lastWrite = date;
            }
        }
      };

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_accelerometer, menu);
    return true;
}
public void onResume() { 
     super.onResume();
     mySensorManager.registerListener(mSensorListener, accSensor, SensorManager.SENSOR_DELAY_GAME);
}
@Override 
public void onDestroy() { 
     emptyOutStream();
     disconnect();
     if (mSensorListener != null) {
         mySensorManager.unregisterListener(mSensorListener);
     }
     super.onDestroy(); 
     myclip.release();
} 
private class ConnectedThread extends Thread {
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket) {
        InputStream tmpIn = null;
        OutputStream tmpOut = null;

        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[256];  // buffer store for the stream
        int bytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);        // Get number of bytes and message in "buffer"
                h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();     // Send to message queue Handler
            } catch (IOException e) {
                break;
            }
        }
    }

    /* Call this from the main activity to send data to the remote device */
    public void write(String message) {

        byte[] msgBuffer = message.getBytes();
        try {
            mmOutStream.write(msgBuffer);
        } catch (IOException e) {

          }
    }
}

我已经阅读了有关该主题的所有内容(BluetoothChat、互联网上人们的项目...),但我很累。非常感谢任何帮助。

--编辑--

我已经设法将输入流输入到我的 texteview 中。我现在的问题是我的应用程序在尝试连接到我的设备(微 Controller 或我的电脑)时卡在进度对话框中(它已连接到设备但进度对话框不会消失)并等待进入。过了一会儿(比如 5-6 秒),即使有东西进来,它仍然卡住,我不得不强制它关闭。我认为问题在于处理程序处理线程的方式。在调试器中没有问题,所有线程都运行正常。

我的代码中的更改是: 在我的连接线程中: `/** 用于连接指定蓝牙设备的线程 */ 公共(public)类 ConnectThread 扩展线程 { 私有(private)字符串地址; 私有(private) bool 连接状态;

    ConnectThread(String MACaddress) {
        address = MACaddress;
        connectionStatus = true;
}

    public void run() {
    // When this returns, it will 'know' about the server, 
       // via it's MAC address. 
        try {
            BluetoothDevice device = btAdapter.getRemoteDevice(address);

            // We need two things before we can successfully connect 
            // (authentication issues aside): a MAC address, which we 
            // already have, and an RFCOMM channel. 
            // Because RFCOMM channels (aka ports) are limited in 
            // number, Android doesn't allow you to use them directly; 
            // instead you request a RFCOMM mapping based on a service 
            // ID. In our case, we will use the well-known SPP Service 
            // ID. This ID is in UUID (GUID to you Microsofties) 
            // format. Given the UUID, Android will handle the 
            // mapping for you. Generally, this will return RFCOMM 1, 
            // but not always; it depends what other BlueTooth services 
            // are in use on your Android device. 
            try { 
                 btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID); 
            } catch (IOException e) { 
                connectionStatus = false;
            } 
        }catch (IllegalArgumentException e) {
            connectionStatus = false;
        }

       // Discovery may be going on, e.g., if you're running a 
       // 'scan for devices' search from your handset's Bluetooth 
       // settings, so we call cancelDiscovery(). It doesn't hurt 
       // to call it, but it might hurt not to... discovery is a 
       // heavyweight process; you don't want it in progress when 
       // a connection attempt is made. 
       btAdapter.cancelDiscovery(); 

       // Blocking connect, for a simple client nothing else can 
       // happen until a successful connection is made, so we 
       // don't care if it blocks. 
       try {
            btSocket.connect(); 
       } catch (IOException e1) {
            try {
                 btSocket.close(); 
            } catch (IOException e2) {
            }
       }

       // Create a data stream so we can talk to server. 
       try { 
            outStream = btSocket.getOutputStream(); 
          } catch (IOException e2) {
            connectionStatus = false;
          }
       try{
        inStream = btSocket.getInputStream();
    }catch (IOException e2){
        connectionStatus = false;
    }
        int bytes; // bytes returned from read()
       // Keep listening to the InputStream until an exception occurs
       while (connectionStatus) {
           try {
               byte[] b = new byte[64];  // buffer store for the stream
               // Read from the InputStream
               bytes = inStream.read(b);        // Get number of bytes and message in "buffer"
               mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, b).sendToTarget();     // Send to message queue Handler
           } catch (IOException e) {
               break;
           }
       }
       // Send final result
       if (connectionStatus) {
        mHandler.obtainMessage(1);
       }else {
        mHandler.sendEmptyMessage(0);
       }
    }
}

` 在我的 onCreate 方法中的 mHandler 中:

 mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
         if (myProgressDialog.isShowing()) {
                myProgressDialog.dismiss();
            }

         // Check if bluetooth connection was made to selected device
            if (msg.what == 1) {
                // Set button to display current status
                connectStat = true;
                connect_button.setText(R.string.connected);
                // Reset the BluCar
                microcOut = 0;
                ledStat = false;
                write(microcOut);
            }else if (msg.what == 2){
                byte[] readBuf = (byte[]) msg.obj;
                String strIncom = new String(readBuf, 0, msg.arg1);                 // create string from bytes array
                sb.append(strIncom);                                                // append string
                int endOfLineIndex = sb.indexOf(".");                            // determine the end-of-line
                if (endOfLineIndex > 0) {                                            // if end-of-line,
                    String sbprint = sb.substring(0, endOfLineIndex);               // extract string
                    sb.delete(0, sb.length());                                      // and clear
                    incoming.setText(sbprint);            // update TextView
                    connectStat = true;
                    connect_button.setText(R.string.connected);
                }else{
                    incoming.setText("Problem!");
                }
            }else {
                // Connection failed
             failToast.show();
            }
        }
    };

我需要做的另一件事是当缓冲区已满时如何清空缓冲区。

PS:感谢大家的帮助,我真的很感激。

最佳答案

作为使用处理程序的替代方法,只需在线程运行时获取信息..

我已经这样做了并且对我有用。

public void run() {
            byte[] buffer = new byte[128];  // buffer store for the stream
            int bytes; // bytes returned from read()

            // Keep listening to the InputStream until an exception occurs
            while (true) {
                try {


                    bytes = mmInStream.read(buffer);
                    byte[] readBuf = (byte[]) buffer;
                    String strIncom = new String(readBuf, 0, bytes);                 // create string from bytes array
                    sb.append(strIncom);                                                // append string
                    int endOfLineIndex = sb.indexOf("\r\n");                            // determine the end-of-line
                    if (endOfLineIndex > 0) {  
                        // add the current string to eol to a local string
                        String sbprint = sb.substring(0, endOfLineIndex);

                        // get the start and end indexes of the heading
                        int startHeading = sb.indexOf("HE");
                        int endHeading = sb.indexOf("/HE");

                        // set the heading
                        Henry.this.setCurrentHeading(sb.substring((startHeading + 2), endHeading));

                        // get the start and end indexes of the front range
                        int startFrontRange = sb.indexOf("FR");
                        int endFrontRange = sb.indexOf("/FR");

                        // get the front range
                        Henry.this.currentFrontRange = sb.substring((startFrontRange + 2), endFrontRange);
             ... ( grab all the information you need here ) ...

                        // debugging output what we have
                        // System.out.println("recv: " + sbprint);

                        // clean out the sb to ready next run
                        sb.delete(0, sb.length());   
                    }

我将从串行连接中检索到的所有信息保存在我的应用程序 (Henry) 中,然后任何想要使用这些信息的 Activity 都会从应用程序中获取它。如果 View 需要对信息有更新的看法,我会在 View 中添加一个计时器,以根据需要随时启动刷新方法。这具有能够在您的 Android 应用程序中的任何位置使用信息的额外优势。

我通过这种方式从 arduino 向设备发送了大约 10 个数据点,并从设备向 arduino 发送了大约 3 个数据点。我在数据点周围添加了自己的标记以识别它们。

希望这对您有所帮助!

关于android - 如何通过蓝牙获取 InputStream 并放入 Textview?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15399181/

相关文章:

Android startActivity - 发生了什么

蓝牙 5.1 到达角向后兼容性

从右到左使用 TextView 的 Android 设置

java - Android:以编程方式仅设置 TextView 的一个填充

android - dagger 简单示例给出了 IllegalStateException

java - Android 默认按钮颜色

android - 如何创建 go 键盘主题?

ios - 我想用蓝牙设备强制打开键盘

ios - 使用 updateValue :forCharacteristic:onSubscribedCentrals on OS X 时蓝牙崩溃

android - 倾斜滚动文本?