java - Android - 从蓝牙读取数据时出错

标签 java android bluetooth arduino

我有一个 Android 应用程序,可以向 Arduino 设备发送数据或从 Arduino 设备检索数据。

package com.arduino.arduinoled1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
  private static final String TAG = "Abdel-Domotic";

  Button ledOn, ledOff;
  Button gateOn, gateOff;
  Button curtOn, curtOff;
  Button getTemp;

  TextView temp;

  OutputStream mmOutputStream;
  InputStream mmInputStream;
  Thread workerThread;
  byte[] readBuffer;
  int readBufferPosition;
  int counter;
  volatile boolean stopWorker;

  private static final int REQUEST_ENABLE_BT = 1;
  private BluetoothAdapter btAdapter = null;
  private BluetoothSocket btSocket = null;
  private OutputStream outStream = null;

  // Well known SPP UUID
  private static final UUID MY_UUID =
      UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

  // Insert your server's MAC address
  private static String address = "20:13:12:05:10:24";

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.d(TAG, "In onCreate()");

    setContentView(R.layout.activity_main);

    ledOn = (Button) findViewById(R.id.ledOn);
    ledOff = (Button) findViewById(R.id.ledOff);
    gateOn = (Button) findViewById(R.id.gateOn);
    gateOff = (Button) findViewById(R.id.gateOff);
    curtOn = (Button) findViewById(R.id.curtOn);
    curtOff = (Button) findViewById(R.id.curtOff);
    getTemp = (Button) findViewById(R.id.gettemp);

    btAdapter = BluetoothAdapter.getDefaultAdapter();
    checkBTState();

    ledOn.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        sendData("1");
        Toast msg = Toast.makeText(getBaseContext(),
            "You have clicked LED On", Toast.LENGTH_SHORT);
        msg.show();
      }
    });

    ledOff.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        sendData("0");
        Toast msg = Toast.makeText(getBaseContext(),
            "You have clicked LED Off", Toast.LENGTH_SHORT);
        msg.show();
      }
    });

    gateOn.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
          sendData("3");
          Toast msg = Toast.makeText(getBaseContext(),
              "You have clicked Gate On", Toast.LENGTH_SHORT);
          msg.show();
        }
      });

      gateOff.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
          sendData("2");
          Toast msg = Toast.makeText(getBaseContext(),
              "You have clicked Gate Off", Toast.LENGTH_SHORT);
          msg.show();
        }
      });

      curtOn.setOnClickListener(new OnClickListener() {
          public void onClick(View v) {
            sendData("5");
            Toast msg = Toast.makeText(getBaseContext(),
                "You have clicked Curton On", Toast.LENGTH_SHORT);
            msg.show();
          }
        });

        curtOff.setOnClickListener(new OnClickListener() {
          public void onClick(View v) {
            sendData("4");
            Toast msg = Toast.makeText(getBaseContext(),
                "You have clicked Curton Off", Toast.LENGTH_SHORT);
            msg.show();
          }
        });

        getTemp.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                sendData("6");
                Toast msg = Toast.makeText(getBaseContext(),
                    "You have clicked Get Temperature", Toast.LENGTH_SHORT);
                msg.show();
                beginListenForData();
            }
        });

  }

  @Override
  public void onResume() {
    super.onResume();

    Log.d(TAG, "...In onResume - Attempting client connect...");

    // Set up a pointer to the remote node using it's address.
    BluetoothDevice device = btAdapter.getRemoteDevice(address);

    // Two things are needed to make a connection:
    //   A MAC address, which we got above.
    //   A Service ID or UUID.  In this case we are using the
    //     UUID for SPP.
    try {
      btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
    } catch (IOException e) {
      errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
    }

    // Discovery is resource intensive.  Make sure it isn't going on
    // when you attempt to connect and pass your message.
    btAdapter.cancelDiscovery();

    // Establish the connection.  This will block until it connects.
    Log.d(TAG, "...Connecting to Remote...");
    try {
      btSocket.connect();
      Log.d(TAG, "...Connection established and data link opened...");
    } catch (IOException e) {
      try {
        btSocket.close();
      } catch (IOException e2) {
        errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
      }
    }

    // Create a data stream so we can talk to server.
    Log.d(TAG, "...Creating Socket...");

    try {
      outStream = btSocket.getOutputStream();
    } catch (IOException e) {
      errorExit("Fatal Error", "In onResume() and output stream creation failed:" + e.getMessage() + ".");
    }
  }

  @Override
  public void onPause() {
    super.onPause();

    Log.d(TAG, "...In onPause()...");

    if (outStream != null) {
      try {
        outStream.flush();
      } catch (IOException e) {
        errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
      }
    }

    try     {
      btSocket.close();
    } catch (IOException e2) {
      errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
    }
  }

  private void checkBTState() {
    // Check for Bluetooth support and then check to make sure it is turned on

    // Emulator doesn't support Bluetooth and will return null
    if(btAdapter==null) { 
      errorExit("Fatal Error", "Bluetooth Not supported. Aborting.");
    } else {
      if (btAdapter.isEnabled()) {
        Log.d(TAG, "...Bluetooth is enabled...");
      } else {
        //Prompt user to turn on Bluetooth
        Intent enableBtIntent = new Intent(btAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
      }
    }
  }

  private void errorExit(String title, String message){
    Toast msg = Toast.makeText(getBaseContext(),
        title + " - " + message, Toast.LENGTH_SHORT);
    msg.show();
    finish();
  }

  private void sendData(String message) {
    byte[] msgBuffer = message.getBytes();

    Log.d(TAG, "...Sending data: " + message + "...");

    try {
      outStream.write(msgBuffer);
    } catch (IOException e) {
      String msg = "In onResume() and an exception occurred during write: " + e.getMessage();
      if (address.equals("00:00:00:00:00:00")) 
        msg = msg + ".\n\nUpdate your server address from 00:00:00:00:00:00 to the correct address on line 37 in the java code";
      msg = msg +  ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + " exists on server.\n\n";

      errorExit("Fatal Error", msg);       
    }
  }

    void beginListenForData() {
        final Handler handler = new Handler();
        final byte delimiter = 10; // This is the ASCII code for a newline
                                    // character

        stopWorker = false;
        readBufferPosition = 0;
        readBuffer = new byte[1024];
        workerThread = new Thread(new Runnable() {
            public void run() {
                while (!Thread.currentThread().isInterrupted() && !stopWorker) {
                    try {
                        int bytesAvailable = mmInputStream.available();
                        if (bytesAvailable > 0) {
                            byte[] packetBytes = new byte[bytesAvailable];
                            mmInputStream.read(packetBytes);
                            for (int i = 0; i < bytesAvailable; i++) {
                                byte b = packetBytes[i];
                                if (b == delimiter) {
                                    byte[] encodedBytes = new byte[readBufferPosition];
                                    System.arraycopy(readBuffer, 0,
                                            encodedBytes, 0,
                                            encodedBytes.length);
                                    final String data = new String(
                                            encodedBytes, "US-ASCII");
                                    readBufferPosition = 0;

                                    handler.post(new Runnable() {
                                        public void run() {
                                            temp.setText(data);
                                        }
                                    });
                                } else {
                                    readBuffer[readBufferPosition++] = b;
                                }
                            }
                        }
                    } catch (IOException ex) {
                        stopWorker = true;
                    }
                }
            }
        });

        workerThread.start();
    }

}

发送部分工作正常,但是当我尝试检索数据时,它给出以下错误消息

06-20 17:28:12.440: D/Abdel-Domotic(6718): ...Connection established and data link opened...
06-20 17:28:12.440: D/Abdel-Domotic(6718): ...Creating Socket...
06-20 17:28:15.470: D/Abdel-Domotic(6718): ...Sending data: 6...
06-20 17:28:15.470: D/BLZ20_ASOCKWRP(6718): asocket_write
06-20 17:28:15.470: I/BLZ20_WRAPPER(6718): blz20_wrp_poll: nfds 2, timeout -1 ms
06-20 17:28:15.470: D/BLZ20_WRAPPER(6718): blz20_wrp_poll: transp poll : (fd 43) returned r_ev [POLLOUT ] (0x4)
06-20 17:28:15.470: D/BLZ20_WRAPPER(6718): blz20_wrp_poll: return 1
06-20 17:28:15.470: D/BLZ20_WRAPPER(6718): blz20_wrp_write: wrote 1 bytes out of 1 on fd 43
06-20 17:28:15.490: W/dalvikvm(6718): threadid=9: thread exiting with uncaught exception (group=0x4001e578)
06-20 17:28:15.500: E/AndroidRuntime(6718): FATAL EXCEPTION: Thread-10
06-20 17:28:15.500: E/AndroidRuntime(6718): java.lang.NullPointerException
06-20 17:28:15.500: E/AndroidRuntime(6718):     at com.arduino.arduinoled1.MainActivity$8.run(MainActivity.java:260)
06-20 17:28:15.500: E/AndroidRuntime(6718):     at java.lang.Thread.run(Thread.java:1019)
06-20 17:28:15.530: D/Abdel-Domotic(6718): ...In onPause()...
06-20 17:28:15.530: D/BLZ20_ASOCKWRP(6718): asocket_abort [43,44,45]
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_shutdown: s 43, how 2
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_shutdown:  fd (-1:43), bta 2, rc 1, wflags 0x800, cflags 0x0, port 9050
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_shutdown: shutdown socket
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_write: wrote 1 bytes out of 1 on fd 45
06-20 17:28:15.530: D/BLZ20_ASOCKWRP(6718): asocket_destroy
06-20 17:28:15.530: D/BLZ20_ASOCKWRP(6718): asocket_abort [43,44,45]
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_shutdown: s 43, how 2
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_shutdown:  fd (-1:43), bta 2, rc 1, wflags 0x800, cflags 0x0, port 9050
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_shutdown: shutdown socket
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_write: wrote 1 bytes out of 1 on fd 45
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_close: s 45
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_close: std close (45)
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_close: s 44
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_close: std close (44)
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): blz20_wrp_close: s 43
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): blz20_wrp_close:  fd (-1:43), bta 2, rc 1, wflags 0x800, cflags 0x0, port 9050
06-20 17:28:15.530: I/BLZ20_WRAPPER(6718): __close_prot_rfcomm: fd 43
06-20 17:28:15.530: I/BTL_IFC(6718): send_ctrl_msg: [BTL_IFC CTRL] send BTLIF_BTS_RFC_CLOSE (BTS) 8 pbytes (hdl 40)
06-20 17:28:15.530: D/BTL_IFC_WRP(6718): wrp_close_s_only: wrp_close_s_only [43] (43:-1) [brcm.bt.btlif]
06-20 17:28:15.530: D/BTL_IFC_WRP(6718): wrp_close_s_only: data socket closed
06-20 17:28:15.530: D/BTL_IFC_WRP(6718): wsactive_del: delete wsock 43 from active list [ad42cbd0]
06-20 17:28:15.530: D/BTL_IFC_WRP(6718): wrp_close_s_only: wsock fully closed, return to pool
06-20 17:28:15.530: D/BLZ20_WRAPPER(6718): btsk_free: success

我的第一个猜测是错误出现在第 260 行,其中表示 int bytesAvailable = mmInputStream.available();

我说得对吗?

有什么问题吗?我该如何修复它?

最佳答案

您的 mmInputStream 对象为 null。您忘记在使用该对象之前创建它。

关于java - Android - 从蓝牙读取数据时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24331200/

相关文章:

android - Wi-Fi Direct 是否可以进行多播?

Android:使用 CountDownTimer 与 Thread.sleep() 的优缺点是什么?

python - 在 python 3 中使用套接字库(RFCOMM 模式)重新连接蓝牙设备?

ios - 在 ios8 xcode6 中找不到 <coreaudiokit/coreaudiokit.h>

java - Eclipse:在独立的 SourceViewer 小部件中启用 Java 错误标记

java - 使用 Java 连接到 FTP

java - 如何在虚拟环境中使用 django-pipeline?

java - Cassandra-Java-driver : com. datastax.driver.core.exceptions.InvalidTypeException : Invalid type, 列是一个列表,但提供了类 java.lang.String

android - Activity <Name> 泄露了最初绑定(bind)在这里的 ServiceConnection com.google.android.vending.licensing.LicenseChecker

ios - 蓝牙可以在我的应用程序未打开的情况下接收数据吗