从一项活动写入蓝牙设备时,android ui挂起

时间:2013-08-19 05:13:11

标签: java android bluetooth rfcomm

我是android + bluetooth的新手。我正在尝试编写一个简单的rfcomm客户端应用程序,该应用程序与在嵌入式平台上运行的rfcomm服务器进行通信。当我的应用程序启动时,它会显示配对设备的列表视图,点击其中一个设备后会跳转到第二个活动。在这个活动中,我打开一个蓝牙插座并连接到它。一旦我跳到一个新的活动,我的UI就会挂起。这个新活动有两个按钮。点击这些按钮,我将数据发送到蓝牙服务器。但是我的UI在这个活动中有点挂起,一旦我点击一个按钮就需要很长时间才能响应并产生错误信息。

我的代码如下:

package com.example.bluetoothapp2;

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

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

// Return Intent extra
public static String EXTRA_DEVICE_ADDRESS = "device_address";

public int REQUEST_ENABLE_BT = 1;// Just defining a flag
//Define a local bluetooth adapter variable to get id of default Adapter
public BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

//Adapter for LIST ITEMS FOR PAIRED DEVICES
public ArrayAdapter<String> mPairedDevicesArrayAdapter;
//Array to store list data for paired device
ArrayList<String> itemPairedArray = new ArrayList<String> ();

//Adapter for LIST ITEMS FOR NEW DEVICES    
public ArrayAdapter<String> mNewDevicesArrayAdapter;
//Array to store list data for paired device
ArrayList<String> itemNewDvcArray = new ArrayList<String> ();

//RECORDING HOW MUCH TIMES BUTTON WAS CLICKED
int clickCounter=0;

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

private void init()
{
    //GetListId from Layout
    ListView pairedListView = (ListView) findViewById(R.id.listPairedDvc);
    ListView newListView = (ListView) findViewById(R.id.listAvailableDvc);

    //Bind the list with listview in layout 
    mPairedDevicesArrayAdapter= new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,itemPairedArray);      
    mNewDevicesArrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,itemNewDvcArray);  

    //Set the adapter to list view (bind a adapter to listview in layout)
    pairedListView.setAdapter(mPairedDevicesArrayAdapter);
    newListView.setAdapter(mNewDevicesArrayAdapter);

    pairedListView.setOnItemClickListener(mDeviceClickListener);

    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

    // Register for broadcasts when discovery has finished
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
    this.registerReceiver(mReceiver, filter);

    // Register for broadcasts when discovery has finished
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
    this.registerReceiver(mReceiver, filter);

    // Get a set of currently paired devices
    Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();

       // If there are paired devices, add each one to the ArrayAdapter
      if (pairedDevices.size() > 0) 
       {
          /*findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);*/
           for (BluetoothDevice device : pairedDevices) 
           {
            itemPairedArray.add(device.getName() + " => "+ device.getAddress());
           }        
       } 
      else 
      {
       itemPairedArray.add("noDevices");
      }

    //Check if device has bluetooth
    if(mBluetoothAdapter == null)
    {
        Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
        finish();
        return;
    }
    //Check if it is enabled or not
    if(!mBluetoothAdapter.isEnabled())
    {
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    }   
}

//METHOD WHICH WILL HANDLE DYNAMIC INSERTION
public void addItems(View v) 
{
    //itemPairedArray.add("Clicked : "+clickCounter++);  //Just for debugging   
    //itemNewDvcArray.add("Clicked : "+clickCounter++);  //Just for debugging
    //itemNewDvcArray.add("NoDevice");
    startDiscovery() ;

   //mPairedDevicesArrayAdapter.notifyDataSetChanged();
   mNewDevicesArrayAdapter.notifyDataSetChanged();       
}

//method to start discovery
private void startDiscovery() 
{
    // TODO Auto-generated method stub
    // If we're already discovering, stop it
    if (mBluetoothAdapter.isDiscovering())
    {
        mBluetoothAdapter.cancelDiscovery();
    }

    // Request discover from BluetoothAdapter
    mBluetoothAdapter.startDiscovery();
}

protected void onDestroy() 
{
    super.onDestroy();

    // Make sure we're not doing discovery anymore
    if (mBluetoothAdapter != null) 
    {
        mBluetoothAdapter.cancelDiscovery();
    }

    // Unregister broadcast listeners
    this.unregisterReceiver(mReceiver);
}    

// The BroadcastReceiver that listens for discovered devices and
// changes the title when discovery is finished
private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
 public void onReceive(Context context, Intent intent) 
 {
        String action = intent.getAction();
        // When discovery finds a device
        if (BluetoothDevice.ACTION_FOUND.equals(action)) 
        {
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

            // If it's already paired, skip it, because it's been listed already
            if (device.getBondState() != BluetoothDevice.BOND_BONDED) 
            {
                    // Add the name and address to an array adapter to show in a ListView
                    itemNewDvcArray.add(device.getName() +" => "+  device.getAddress());               
            }                   
        }           
    }
   };       

  // The on-click listener for all devices in the ListViews
   private OnItemClickListener mDeviceClickListener = new OnItemClickListener() 
   {
   public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3)
   {
       // Get the device MAC address, which is the last 17 chars in the View
       String info = ((TextView) v).getText().toString();
       String address = info.substring(info.length() - 17);

       //Toast.makeText(getApplicationContext(), address, 0).show();
       // Create the result Intent and include the MAC address
       Intent intent = new Intent(MainActivity.this,ConnectActivity.class);
       intent.putExtra(EXTRA_DEVICE_ADDRESS, address);

       startActivity(intent);
       }
   };
}


    package com.example.bluetoothapp2;

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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ConnectActivity extends Activity {

// Unique UUID for this application
public static final UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

String address;
protected static final int SUCCESS_CONNECT = 0;
protected static final int MESSAGE_READ = 1;
public BluetoothSocket mmSocket;
public InputStream mmInStream;
public OutputStream mmOutStream;    
String tag = "debugging";

private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) 
    {
        // TODO Auto-generated method stub
        Log.i(tag, "in handler");
        super.handleMessage(msg);
        switch(msg.what){
        case SUCCESS_CONNECT:
            // DO something
            ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
            //Toast.makeText(getApplicationContext(), "CONNECT", 0).show();
            String s = "successfully connected";
            connectedThread.write(s.getBytes());
            Log.i(tag, "connected");
            break;
        case MESSAGE_READ:
            byte[] readBuf = (byte[])msg.obj;
            String string = new String(readBuf);
            //Toast.makeText(getApplicationContext(), string, 0).show();
            break;
        }
    }
};

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

    // Get the message from the intent
    Intent intent = getIntent();
    address = intent.getStringExtra(MainActivity.EXTRA_DEVICE_ADDRESS);

    // Create the text view
    TextView textView = (TextView)findViewById(R.id.addrs);
    //textView.setTextSize(40);
    textView.setText(address);

    connect();  
}

//method to start discovery
public void connect() 
{
    // Get the BluetoothDevice object
    BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

    //Toast.makeText(getApplicationContext(),"connecting", 0).show();
    ConnectThread  connect = new ConnectThread(device) ;
    connect.start();
}

//Thread for establising a connection
private class ConnectThread extends Thread 
{
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device) 
    {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        BluetoothSocket tmp = null;
        mmDevice = device;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID_INSECURE);
        } catch (IOException e) { }
        mmSocket = tmp;
    }

    public void run() 
    {
        // Cancel discovery because it will slow down the connection
        mBluetoothAdapter.cancelDiscovery();

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        //manageConnectedSocket(mmSocket);
        mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() 
    {
        try 
        {
            mmSocket.close();
        } catch (IOException e) { }
    }
}

private class ConnectedThread extends Thread 
{
    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = 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 ;  // 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
                buffer = new byte[1024];
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
            } catch (IOException e) {
                break;
            }
        }
    }

    /* Call this from the main activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            //a delay of 20ms occurs after each flush...
            mmOutStream.write(bytes);
            mmOutStream.flush();
        } catch (IOException e) { }
    }

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

//method to start discovery
public void ledOn(View v ) throws IOException
{
    //Toast.makeText(getApplicationContext(),"LED ON", 0).show();
    mmOutStream.write('o');
}

//method to start discovery
public void ledOff(View v ) throws IOException
{
    //Toast.makeText(getApplicationContext(),"LED OFF", 0).show();
    mmOutStream.write('f');
}

public void disconnectCntn(View v ) throws IOException
{
    String msg = "Disconnect";
    mmOutStream.write(msg.getBytes());
    // close the connection
    mmOutStream.close();
    mmInStream.close();
    // close the connection
    if (mmSocket != null)
        try {
            mmSocket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    return;
}

}

我收到以下错误消息

    08-19 13:09:55.833: D/AndroidRuntime(5221): Shutting down VM
08-19 13:09:55.834: W/dalvikvm(5221): threadid=1: thread exiting with uncaught exception (group=0x41cc29a8)
08-19 13:09:55.847: E/AndroidRuntime(5221): FATAL EXCEPTION: main
08-19 13:09:55.847: E/AndroidRuntime(5221): java.lang.IllegalStateException: Could not execute method of the activity
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.view.View$1.onClick(View.java:3606)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.view.View.performClick(View.java:4211)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.view.View$PerformClick.run(View.java:17446)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.os.Handler.handleCallback(Handler.java:725)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.os.Handler.dispatchMessage(Handler.java:92)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.os.Looper.loop(Looper.java:153)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.app.ActivityThread.main(ActivityThread.java:5299)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at java.lang.reflect.Method.invokeNative(Native Method)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at java.lang.reflect.Method.invoke(Method.java:511)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at dalvik.system.NativeStart.main(Native Method)
08-19 13:09:55.847: E/AndroidRuntime(5221): Caused by: java.lang.reflect.InvocationTargetException
08-19 13:09:55.847: E/AndroidRuntime(5221):     at java.lang.reflect.Method.invokeNative(Native Method)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at java.lang.reflect.Method.invoke(Method.java:511)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.view.View$1.onClick(View.java:3601)
08-19 13:09:55.847: E/AndroidRuntime(5221):     ... 11 more
08-19 13:09:55.847: E/AndroidRuntime(5221): Caused by: java.io.IOException: [JSR82] write: write() failed.
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.bluetooth.BluetoothSocket.write(BluetoothSocket.java:702)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at android.bluetooth.BluetoothOutputStream.write(BluetoothOutputStream.java:56)
08-19 13:09:55.847: E/AndroidRuntime(5221):     at com.example.bluetoothapp2.ConnectActivity.ledOn(ConnectActivity.java:213)
08-19 13:09:55.847: E/AndroidRuntime(5221):     ... 14 more

抱歉这么长的帖子。知道为什么UI会挂起以及可能导致错误的原因。

由于 多摩

1 个答案:

答案 0 :(得分:0)

ConnectedThread是实例化的,但是我们跳过了启动线程的部分,花哨的调用start()就可以了? connectedThread.start(),它将使它在套接字上监听任何写入的数据。

ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
//add this line
connectedThread.start()
//Toast.makeText(getApplicationContext(), "CONNECT", 0).show();
String s = "successfully connected";
connectedThread.write(s.getBytes());