2017-07-17 163 views
0

我想創建一個應用程序,允許一個字符串從一個Android手機發送到另一個。下面提供了這個代碼。但是,它並不工作,因爲我一直從pairDevice()部分的try catch代碼塊中獲取異常。有誰知道我爲什麼會得到這個?如何通過藍牙發送/接收消息android studio

import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice; 
import android.bluetooth.BluetoothSocket; 
import android.content.Intent; 
import android.os.ParcelUuid; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.EditText; 
import android.widget.TextView; 
import android.widget.Toast; 

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.Scanner; 
import java.util.Set; 

public class MainActivity extends AppCompatActivity { 

    InputStream inStream; 
    OutputStream outputStream; 
    private static final int REQUEST_ENABLE_BT = 1; 

    public void pairDevice() { 
     BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
     if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new 
      Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);} 

     Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices(); 
     if (pairedDevices.size() > 0) { 
      Object[] devices = pairedDevices.toArray(); 
      BluetoothDevice device = (BluetoothDevice) devices[0]; 
      ParcelUuid[] uuid = device.getUuids(); 
      try { 
       BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(uuid[0].getUuid()); 
       socket.connect(); 
       Toast.makeText(this, "Socket connected", Toast.LENGTH_LONG).show(); 
       outputStream = socket.getOutputStream(); 
       inStream = socket.getInputStream(); 
      } catch (IOException e) { 
       Toast.makeText(this, "Exception found", Toast.LENGTH_LONG).show(); 
      } 

     } 
    } 


public void SendMessage(View v) { 
    EditText outMessage = (EditText) findViewById(R.id.editText); 
    try { 
     if (outputStream != null) 
      outputStream.write(outMessage.toString().getBytes()); 
      TextView displayMessage = (TextView) findViewById(R.id.textView); 
      Scanner s = new Scanner(inStream).useDelimiter("\\A"); 
      displayMessage.setText(s.hasNext() ? s.next() : ""); 
    } catch (IOException e) {/*Do nothing*/} 
    Toast.makeText(this,"No output stream", Toast.LENGTH_LONG).show(); 
} 





@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    pairDevice(); 
} 

}

回答

1

我很少進行修改的程序: -

首先,我調整了代碼負責創建ConnectThread的藍牙連接。

2)添加AcceptThread負責偵聽傳入連接並ConnectedThread保持BTConnection,發送的數據,並分別 通過輸入/輸出流接收輸入的數據。 3)創建2個按鈕來啓動ConnectThread和AcceptThread。

注意:確保兩個設備配對,並且您 試圖連接到該設備是在列表的頂部(或只是無論從設備上刪除所有 配對設備,只配對您要連接的設備 )。此外,還必須ConnectThread

MAINACTIVITY.JAVA

public class MainActivity extends AppCompatActivity { 

    private static final UUID MY_UUID_INSECURE = 
      UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"); 

    private static final int REQUEST_ENABLE_BT = 1; 
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
    private BluetoothDevice mmDevice; 
    private UUID deviceUUID; 
    ConnectedThread mConnectedThread; 
    private Handler handler; 

    String TAG = "MainActivity"; 
    EditText send_data; 
    TextView view_data; 
    StringBuilder messages; 






    public void pairDevice(View v) { 

     Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices(); 
     Log.e("MAinActivity", "" + pairedDevices.size()); 
     if (pairedDevices.size() > 0) { 
      Object[] devices = pairedDevices.toArray(); 
      BluetoothDevice device = (BluetoothDevice) devices[0]; 
      //ParcelUuid[] uuid = device.getUuids(); 
      Log.e("MAinActivity", "" + device); 
      //Log.e("MAinActivity", "" + uuid) 

      ConnectThread connect = new ConnectThread(device,MY_UUID_INSECURE); 
      connect.start(); 

     } 
    } 

    private class ConnectThread extends Thread { 
     private BluetoothSocket mmSocket; 

     public ConnectThread(BluetoothDevice device, UUID uuid) { 
      Log.d(TAG, "ConnectThread: started."); 
      mmDevice = device; 
      deviceUUID = uuid; 
     } 

     public void run(){ 
      BluetoothSocket tmp = null; 
      Log.i(TAG, "RUN mConnectThread "); 

      // Get a BluetoothSocket for a connection with the 
      // given BluetoothDevice 
      try { 
       Log.d(TAG, "ConnectThread: Trying to create InsecureRfcommSocket using UUID: " 
         +MY_UUID_INSECURE); 
       tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID_INSECURE); 
      } catch (IOException e) { 
       Log.e(TAG, "ConnectThread: Could not create InsecureRfcommSocket " + e.getMessage()); 
      } 

      mmSocket = tmp; 

      // Make a connection to the BluetoothSocket 

      try { 
       // This is a blocking call and will only return on a 
       // successful connection or an exception 
       mmSocket.connect(); 

      } catch (IOException e) { 
       // Close the socket 
       try { 
        mmSocket.close(); 
        Log.d(TAG, "run: Closed Socket."); 
       } catch (IOException e1) { 
        Log.e(TAG, "mConnectThread: run: Unable to close connection in socket " + e1.getMessage()); 
       } 
       Log.d(TAG, "run: ConnectThread: Could not connect to UUID: " + MY_UUID_INSECURE); 
      } 

      //will talk about this in the 3rd video 
      connected(mmSocket); 
     } 
     public void cancel() { 
      try { 
       Log.d(TAG, "cancel: Closing Client Socket."); 
       mmSocket.close(); 
      } catch (IOException e) { 
       Log.e(TAG, "cancel: close() of mmSocket in Connectthread failed. " + e.getMessage()); 
      } 
     } 
    } 

    private void connected(BluetoothSocket mmSocket) { 
     Log.d(TAG, "connected: Starting."); 

     // Start the thread to manage the connection and perform transmissions 
     mConnectedThread = new ConnectedThread(mmSocket); 
     mConnectedThread.start(); 
    } 

    private class ConnectedThread extends Thread { 
     private final BluetoothSocket mmSocket; 
     private final InputStream mmInStream; 
     private final OutputStream mmOutStream; 

     public ConnectedThread(BluetoothSocket socket) { 
      Log.d(TAG, "ConnectedThread: Starting."); 

      mmSocket = socket; 
      InputStream tmpIn = null; 
      OutputStream tmpOut = null; 



      try { 
       tmpIn = mmSocket.getInputStream(); 
       tmpOut = mmSocket.getOutputStream(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      mmInStream = tmpIn; 
      mmOutStream = tmpOut; 
     } 

     public void run(){ 
      byte[] buffer = new byte[1024]; // buffer store for the stream 

      int bytes; // bytes returned from read() 

      // Keep listening to the InputStream until an exception occurs 
      while (true) { 
       // Read from the InputStream 
       try { 
        bytes = mmInStream.read(buffer); 
        final String incomingMessage = new String(buffer, 0, bytes); 
        Log.d(TAG, "InputStream: " + incomingMessage); 

        runOnUiThread(new Runnable() { 

         @Override 
         public void run() { 
          view_data.setText(incomingMessage); 
         } 
        }); 


       } catch (IOException e) { 
        Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage()); 
        break; 
       } 
      } 
     } 


     public void write(byte[] bytes) { 
      String text = new String(bytes, Charset.defaultCharset()); 
      Log.d(TAG, "write: Writing to outputstream: " + text); 
      try { 
       mmOutStream.write(bytes); 
      } catch (IOException e) { 
       Log.e(TAG, "write: Error writing to output stream. " + e.getMessage()); 
      } 
     } 

     /* Call this from the main activity to shutdown the connection */ 
     public void cancel() { 
      try { 
       mmSocket.close(); 
      } catch (IOException e) { } 
     } 
    } 


    public void SendMessage(View v) { 
     byte[] bytes = send_data.getText().toString().getBytes(Charset.defaultCharset()); 
     mConnectedThread.write(bytes); 
    } 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 


     send_data =(EditText) findViewById(R.id.editText); 
     view_data = (TextView) findViewById(R.id.textView); 

     if (bluetoothAdapter != null && !bluetoothAdapter.isEnabled()) { 
      Intent enableBtIntent = new 
        Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); 
     } 


    } 

    public void Start_Server(View view) { 

     AcceptThread accept = new AcceptThread(); 
     accept.start(); 

    } 

    private class AcceptThread extends Thread { 

     // The local server socket 
     private final BluetoothServerSocket mmServerSocket; 

     public AcceptThread(){ 
      BluetoothServerSocket tmp = null ; 

      // Create a new listening server socket 
      try{ 
       tmp = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord("appname", MY_UUID_INSECURE); 

       Log.d(TAG, "AcceptThread: Setting up Server using: " + MY_UUID_INSECURE); 
      }catch (IOException e){ 
       Log.e(TAG, "AcceptThread: IOException: " + e.getMessage()); 
      } 

      mmServerSocket = tmp; 
     } 

     public void run(){ 
      Log.d(TAG, "run: AcceptThread Running."); 

      BluetoothSocket socket = null; 

      try{ 
       // This is a blocking call and will only return on a 
       // successful connection or an exception 
       Log.d(TAG, "run: RFCOM server socket start....."); 

       socket = mmServerSocket.accept(); 

       Log.d(TAG, "run: RFCOM server socket accepted connection."); 

      }catch (IOException e){ 
       Log.e(TAG, "AcceptThread: IOException: " + e.getMessage()); 
      } 

      //talk about this is in the 3rd 
      if(socket != null){ 
       connected(socket); 
      } 

      Log.i(TAG, "END mAcceptThread "); 
     } 

     public void cancel() { 
      Log.d(TAG, "cancel: Canceling AcceptThread."); 
      try { 
       mmServerSocket.close(); 
      } catch (IOException e) { 
       Log.e(TAG, "cancel: Close of AcceptThread ServerSocket failed. " + e.getMessage()); 
      } 
     } 

    } 

activity_main.xml中啓動AcceptThread

<?xml version="1.0" encoding="utf-8"?> 
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context="com.example.hpi5.bluethoothshot.MainActivity" 
    tools:layout_editor_absoluteY="81dp" 
    tools:layout_editor_absoluteX="0dp"> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Hello World!" 
     android:id="@+id/textView" 
     tools:layout_constraintTop_creator="1" 
     tools:layout_constraintRight_creator="1" 
     app:layout_constraintRight_toRightOf="parent" 
     android:layout_marginTop="58dp" 
     tools:layout_constraintLeft_creator="1" 
     app:layout_constraintLeft_toLeftOf="parent" 
     app:layout_constraintTop_toTopOf="parent" /> 

    <EditText 
     android:id="@+id/editText" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:ems="10" 
     android:inputType="textPersonName" 
     android:text="Name" 
     tools:layout_constraintTop_creator="1" 
     tools:layout_constraintRight_creator="1" 
     app:layout_constraintRight_toRightOf="parent" 
     android:layout_marginTop="153dp" 
     tools:layout_constraintLeft_creator="1" 
     app:layout_constraintLeft_toLeftOf="parent" 
     app:layout_constraintTop_toTopOf="parent" /> 

    <Button 
     android:id="@+id/button" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button" 
     android:onClick="SendMessage" 
     tools:layout_constraintTop_creator="1" 
     tools:layout_constraintRight_creator="1" 
     app:layout_constraintRight_toRightOf="parent" 
     android:layout_marginTop="22dp" 
     app:layout_constraintTop_toBottomOf="@+id/editText" 
     tools:layout_constraintLeft_creator="1" 
     app:layout_constraintLeft_toLeftOf="parent" /> 

    <Button 
     android:id="@+id/button2" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Server" 
     android:onClick="Start_Server" 
     android:layout_marginEnd="53dp" 
     tools:layout_constraintRight_creator="1" 
     tools:layout_constraintBottom_creator="1" 
     app:layout_constraintBottom_toBottomOf="parent" 
     app:layout_constraintRight_toRightOf="parent" 
     android:layout_marginBottom="84dp" /> 

    <Button 
     android:id="@+id/button3" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="ConnectionREq" 
     android:onClick="pairDevice" 
     android:layout_marginStart="34dp" 
     tools:layout_constraintTop_creator="1" 
     tools:layout_constraintBottom_creator="1" 
     app:layout_constraintBottom_toBottomOf="@+id/button2" 
     tools:layout_constraintLeft_creator="1" 
     app:layout_constraintLeft_toLeftOf="parent" 
     app:layout_constraintTop_toTopOf="@+id/button2" 
     android:layout_marginLeft="30dp" 
     app:layout_constraintVertical_bias="0.0" /> 

</android.support.constraint.ConstraintLayout> 
+0

非常感謝!該應用程序完美工作,我一直在網上搜索教程,你的答案是迄今爲止唯一對我有用的東西。還有一個問題,應該適用於任何藍牙設備(例如Apple to Apple或Android to Apple),還是隻能從Android到Android。 –

+0

在iOS(支持iPhone,iPad,iPod等)下運行Android應用程序時,*本身不可能* – rayan

2

異常說明會defenitely幫助,但我99%肯定該系統會阻止您執行的UI線程內插座連接代碼 - 所以你需要創建一個新的線程,請將您的插座創建和套接字連接代碼到該線程,最後創建一個回調,這將指示偵聽器連接已執行或失敗。

請注意,Android將阻止大多數你嘗試做UI線程內部網絡相關耗時的操作,因爲它使UI所以sloooow ;-)

1

兩大PROBLEMS-

1 )connect()是一個阻塞調用,您應該始終在與主活動(UI)線程分開的線程中執行此連接過程。您正在主線程中執行此操作。

注意:您應該始終調用cancelDiscovery(),以確保在打電話之前連接()的 設備沒有進行設備發現。 如果發現正在進行中,則連接嘗試是 明顯變慢,並且更有可能失敗。

2)如果您也在第二個設備上使用相同的代碼(以便您可以發送或接收數據),那麼我看不到任何呼叫accept()accept()監聽連接請求。 再次,accept()調用是一個阻塞調用,它不應該在主活動UI線程中執行,以便您的應用程序仍可以響應其他用戶交互。

服務器組件接受傳入連接

簡體螺紋:

private class AcceptThread extends Thread { 
    private final BluetoothServerSocket mmServerSocket; 

    public AcceptThread() { 
     // Use a temporary object that is later assigned to mmServerSocket 
     // because mmServerSocket is final. 
     BluetoothServerSocket tmp = null; 
     try { 
      // MY_UUID is the app's UUID string, also used by the client code. 
      tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); 
     } catch (IOException e) { 
      Log.e(TAG, "Socket's listen() method failed", e); 
     } 
     mmServerSocket = tmp; 
    } 

    public void run() { 
     BluetoothSocket socket = null; 
     // Keep listening until exception occurs or a socket is returned. 
     while (true) { 
      try { 
       socket = mmServerSocket.accept(); 
      } catch (IOException e) { 
       Log.e(TAG, "Socket's accept() method failed", e); 
       break; 
      } 

      if (socket != null) { 
       // A connection was accepted. Perform work associated with 
       // the connection in a separate thread. 
       manageMyConnectedSocket(socket); 
       mmServerSocket.close(); 
       break; 
      } 
     } 
    } 

    // Closes the connect socket and causes the thread to finish. 
    public void cancel() { 
     try { 
      mmServerSocket.close(); 
     } catch (IOException e) { 
      Log.e(TAG, "Could not close the connect socket", e); 
     } 
    } 
} 

Android文檔 - BLUETOOTH

+0

感謝您的詳細答覆。我已將您的建議實施到我的計劃中。但是,只要我點擊發送按鈕,應用程序就會崩潰。通過多次運行應用程序,我知道這是由於兩行代碼Scanner s = new Scanner(inStream).useDelimiter(「\\ A」); displayMessage.setText(s.hasNext()?s.next():「」);你能建議爲什麼或者可能給出一些代碼,將輸出流中的文本並將其設置爲TextView上的文本。 –