2016-05-18 112 views
2

我正在學習Android藍牙編程。我從Google的Android開發人員網站上覆制了大部分代碼以供學習。這個想法是監聽服務器上的連接是在一個新線程中完成的,而不會阻塞UI線程。當收到連接請求時,連接在另一個線程上完成,最後在另一個線程上完成通信。Android藍牙:從UI線程開始的線程阻塞UI線程

問題是,當我從UI線程啓動偵聽線程時,它會自動阻塞,並且沒有顯示UI(凍結)。下面是示例代碼:

public void onCreate(Bundle savedInstance) { 
    super.onCreate(savedInstance); 
    setContentView(R.layout.activity_main); 
    ... 

    badapter = BluetoothAdapter.getDefaultAdapter(); 
    if (badapter == null) { 
     Toast.makeText(this, "No bluetooth device.", Toast.LENGTH_SHORT).show(); 
     return; 
    } 

    if (!badapter.isEnabled()) { 
     Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show(); 
     return; 
    } 

    pairedDevices = new HashMap<String, String>(); 
    discoveredDevices = new HashMap<String, String>(); 

    showDevices(); 
    registerBroadcastReceiver(); 

    //this thread blocks UI thread 
    ListenThread listen = new ListenThread(); 
    listen.run(); 
} 

而且聽螺紋:

public class ListenThread extends Thread { 
    MainActivity main; 
    CommunicateThread communicateThread; 
    private final BluetoothServerSocket serverSocket; 

    public ListenThread() { 
     main = MainActivity.getInstance(); 

     BluetoothServerSocket tmp = null; 
     try { 
      tmp = main.badapter.listenUsingRfcommWithServiceRecord(main.NAME, main.MYUUID); 
     } catch (final IOException e) { 
      main.handler.post(new Runnable() { 
       @Override 
       public void run() { 
        Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 
       } 
      }); 
     } 
     serverSocket = tmp; 
    } 

    public void run() { 
     BluetoothSocket socket = null; 

     //keep listening until exception occurs or a socket is returned 
     while (true) { 
      try { 
       socket = serverSocket.accept(); 
      } catch (final IOException e) { 
       main.handler.post(new Runnable() { 
        @Override 
        public void run() { 
         Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 
        } 
       }); 
       break; 
      } 

      // If a connection was accepted 
      if (socket != null) { 
       //call communication thread once connection is established 
       communicateThread = new CommunicateThread(socket); 
       communicateThread.run(); 

       try { 
        serverSocket.close(); 
       } catch (final IOException e) { 
        main.handler.post(new Runnable() { 
         @Override 
         public void run() { 
          Toast.makeText(main, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); 
         } 
        }); 
       } 
       break; 
      } 
     } 
    } 
} 
+3

我認爲需要使用'listen.start();'來啓動Thread而不是調用run方法 –

+0

我真是太傻了!這可能是原因嗎? – birraa

+0

這是原因。這是否意味着當我調用run時,它是在UI線程中執行的呢? – birraa

回答

0

我有同樣的問題。我的理解是,每次你進行硬件調用,在這種情況下,藍牙,你應該在另一個線程中。我將isEnabled()調用移至其他線程,並解決了問題。

0

你正在主線程上調用listen.run(),使它在主線程上運行。你應該調用listen.start(),它將產生一個獨立的線程,run()方法將被執行。

給予處理程序的Runnable將在主線程上執行,但Handler用於主線程。