蓝牙聊天

最近通过Google学习了两部设备之间通过蓝牙连接实现聊天的功能,以下为代码:

/**
 * BlueToothChat:开启蓝牙,300s可见,连接设备,线程UI处理,聊天设置,整个界面功能的实现
 * @author micro
 *
 */

public class BlueToothChat extends Activity {

    //Handler的处理码
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;

    //设备名和TOAST
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";

    //请求码
    public static final int REQUEST_CONNECT_DEVICE = 2;
    public static final int REQUEST_ENABLE_BT = 3;

    //控件
    private ListView mConversation;
    private EditText mEdit;
    private Button sendBtn;

    private String mConnectedServiceName;             //设备名
    private ArrayAdapter<String> mConversationAdapter;  //聊天设配器
    private StringBuffer mOutString ;                   //输出的信息

    private BluetoothAdapter mBluetoothAdapter = null;         //蓝牙适配器
    private BlueToothChatService mBlueToothChatService = null;  //服务端

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //获取默认的蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        if(mBluetoothAdapter==null){

            Toast.makeText(getApplicationContext(), "此设备不支持蓝牙", Toast.LENGTH_SHORT).show();
            this.finish();   //结束
            return ;
        }

    }
    /**
     * 在onStart方法中开启蓝牙
     */
    @Override
    public void onStart(){
        super.onStart();

        //如果蓝牙没开,则开启蓝牙,开启后回调REQUEST_ENABLE_BT
        if(!mBluetoothAdapter.isEnabled()){

            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent,REQUEST_ENABLE_BT);

        }else{

            if(mBlueToothChatService == null){
                //设置聊天
                setupChat();

            }

        }

    }
    /**
     * 在onResume方法中开启服务端里的线程
     */

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

        //只有满足以下的两个条件之后我们才会开启
        if(mBlueToothChatService!=null){

            if(mBlueToothChatService.getState()==BlueToothChatService.STATE_NONE){

                mBlueToothChatService.start();
            }
        }

    }

    /**
     * 聊天设置,初始化及监听
     */
    private void setupChat() {
        // TODO Auto-generated method stub

        //初始化ListView

        mConversationAdapter = new
                ArrayAdapter<String>(this,R.layout.message);

        mConversation = (ListView)findViewById(R.id.chat_list);

        mConversation.setAdapter(mConversationAdapter);

        //发送按钮
        sendBtn = (Button)findViewById(R.id.send_btn);
        sendBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub

                TextView mTextView = (TextView)findViewById(R.id.edit_text);
                String message = mTextView.getText().toString();
                sendMessage(message);

            }

        });

        //Edit监听
        mEdit = (EditText)findViewById(R.id.edit_text);
        mEdit.setOnEditorActionListener(mWriteLisentner);
        //初始化
        mBlueToothChatService = new BlueToothChatService(this,handler);

        mOutString = new StringBuffer("");

        }

    //发送信息到Handler处理
    private void sendMessage(String message) {
                // TODO Auto-generated method stub

                if(mBlueToothChatService.getState()!=BlueToothChatService.STATE_CONNECTED){

                    Toast.makeText(getApplicationContext(), R.string.not_connected, Toast.LENGTH_SHORT).show();

                    return ;

                }

                if(message.length()>0){

                    //在这里发送信息
                    byte[] send = message.getBytes();

                    mBlueToothChatService.write(send);

                    //重置清空
                    mOutString.setLength(0);

                    mEdit.setText(mOutString);

                }

    }

    /**
     * 监听编辑器的结果
     */
    private TextView.OnEditorActionListener mWriteLisentner = new TextView.OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
            // TODO Auto-generated method stub
            //如果结果为空,提示
            if(actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP){

                String message = view.getText().toString();
                sendMessage(message);
            }
            return true;
        }
    };

    //通过ActionBar显示
    private final void setStatus(int resId){
        final ActionBar actionBar = getActionBar();
        actionBar.setSubtitle(resId);
    }

    public final void setStatus(CharSequence subTitle){
        final ActionBar actionBar = getActionBar();
        actionBar.setSubtitle(subTitle);
    }

    //handler处理机制
    private Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg){
            switch(msg.what){

            case MESSAGE_STATE_CHANGE:
                switch(msg.arg1){

                case BlueToothChatService.STATE_CONNECTED:

                    setStatus( "connected to "+mConnectedServiceName);
                    mConversationAdapter.clear();

                    break;
                case BlueToothChatService.STATE_CONNECTING:
                    setStatus(R.string.title_connecting);
                    break;
                case BlueToothChatService.STATE_LISTEN:
                case BlueToothChatService.STATE_NONE:
                    setStatus(R.string.title_not_connected);
                    break;

                }
                break;

            case MESSAGE_WRITE:
                byte[] writebuf = (byte[]) msg.obj;
                String writemessage = new String(writebuf);
                mConversationAdapter.add("Me:  "+writemessage);

                break;
            case MESSAGE_READ:
                byte[] readbuf = (byte[])msg.obj;
                String readmessage = new String(readbuf, 0, msg.arg1);
                mConversationAdapter.add(mConnectedServiceName+":  "+readmessage);

                break;
            case MESSAGE_TOAST:
                //这个好像没用到
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_DEVICE_NAME:
                //保存链接设备的名称
                mConnectedServiceName = msg.getData().getString(DEVICE_NAME);
                Toast.makeText(getApplicationContext(), "connect to "+mConnectedServiceName, Toast.LENGTH_SHORT).show();
                break;

            }
        }

    };

    //请求码的处理
    @Override
    public void onActivityResult(int requestCode,int resultCode,Intent data){

        //通过请求码来判断是否与结果码一样,然后做处理
        switch(requestCode){
        //请求成功则链接设备
        case REQUEST_CONNECT_DEVICE:
            if(resultCode == Activity.RESULT_OK){
                connectDevice(data);
            }
            break;
        case REQUEST_ENABLE_BT:
            if(resultCode == Activity.RESULT_OK){
                //设备可用,进入setupChat()
                setupChat();
            }else{
                Toast.makeText(getApplicationContext(), R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                finish();
            }

        }

    }

    /**
     * 连接设备
     * @param data
     */

    public void connectDevice(Intent data) {
        // TODO Auto-generated method stub
        //获取Mac地址
        String address = data.getExtras().
                getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);

        //通过地址获取设备
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);

        //然后连接
        mBlueToothChatService.connect(device);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu){

        MenuInflater inflater = getMenuInflater();

        inflater.inflate(R.menu.option_menu, menu);
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item){

        Intent serverIntent =null;
        switch (item.getItemId()) {

        //扫描连接
        case R.id.connect_scan:
            serverIntent = new Intent(this,DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);

            return true;

        //可发现300s内
        case R.id.discoverable:

            ensureDiscovery();

            return true;
        }
        return false;

    }

    //设置300s可被发现
    private void ensureDiscovery() {
        // TODO Auto-generated method stub

        if(mBluetoothAdapter.getScanMode()!=BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){

            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }

    }

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

    @Override
    public void onStop(){
        super.onStop();
    }

    @Override
    public void onDestroy(){
        super.onDestroy();
        if(mBlueToothChatService!=null){
            mBlueToothChatService.stop();
        }
    }

}

接下来是


/**
 * BlueToothChatService实现的线程开启,关闭,管理以及连接
 * @author micro
 *
 */

public class BlueToothChatService {

    private static int mState;

    public static final String NAME = "BlueToothChat";

    public static final UUID MY_UUID = UUID.fromString("0001101-0000-1000-8000-00805F9B34FB");

    //
    private final  Handler mHandler ;

    //三个线程
    private ConnectThread mmConnectThread ;
    private ConnectedThread mmConnectedThread;
    private AcceptThread mmAcceptThread;

    //表示当前的连接状态
    public static final int STATE_NONE = 0;
    public static final int STATE_LISTEN = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_CONNECTED = 3;

    //蓝牙适配器
    private BluetoothAdapter mAdapter;

    //构造器初始化
    public BlueToothChatService(Context context, Handler handler) {
        // TODO Auto-generated constructor stub
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        mState = STATE_NONE;
        mHandler = handler;

    }

    //设置当前状态
    public synchronized void setState(int state){

        mState = state;

        //UI线程处理
        mHandler.obtainMessage(BlueToothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();

    }

    /**
     * Return the current connection state.
     */
    public synchronized int getState() {
        return mState;
    }

    /**
     * 开启AcceptThread线程
     */

    public synchronized void start() {
        // TODO Auto-generated method stub

        if(mmConnectedThread!=null){
            mmConnectedThread.cancel();
            mmConnectedThread = null;
        }

        if(mmConnectThread!=null){
            mmConnectThread.cancel();
            mmConnectThread=null;
        }

        //服务端线程开启
        if(mmAcceptThread == null){

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

        }

        //设置为监听状态
        setState(STATE_LISTEN);

    }

    /**
     * 开启一个设备连接线程
     * @param device
     */

    public synchronized void connect(BluetoothDevice device) {
        // TODO Auto-generated method stub

        if(mState == STATE_CONNECTING){

            if(mmConnectThread!=null){
                mmConnectThread.cancel();
                mmConnectThread = null;
            }
        }

        if(mmConnectedThread!=null){
            mmConnectedThread.cancel();
            mmConnectedThread = null;
        }

        //开启
        mmConnectThread = new ConnectThread(device);
        mmConnectThread.start();

        setState(STATE_CONNECTING);

    }

    /**
     * 开启一个已经连接的线程来管理蓝牙连接
     * Start the ConnectedThread to begin managing a Bluetooth connection
     * @param socket
     * @param device
     * @param socketType
     */
    public synchronized void connected(BluetoothSocket socket,
            BluetoothDevice device, final String socketType){

        if(mmConnectedThread!=null){
            mmConnectedThread.cancel();
            mmConnectedThread = null;
        }

        if(mmConnectThread!=null){
            mmConnectThread.cancel();
            mmConnectThread = null;
        }

        if(mmAcceptThread!=null){
            mmAcceptThread.cancel();
            mmAcceptThread = null;
        }

        mmConnectedThread = new ConnectedThread(socket, socketType);
        mmConnectedThread.start();

        // Send the name of the connected device back to the UI Activity

        Message message = mHandler.obtainMessage(BlueToothChat.MESSAGE_DEVICE_NAME);

        Bundle bundle = new Bundle();
        bundle.putString(BlueToothChat.DEVICE_NAME, device.getName());

        message.setData(bundle);

        mHandler.sendMessage(message);

        setState(STATE_CONNECTED);
    }

    /**
     * 停止所有的线程
     */

    public synchronized void stop() {
        // TODO Auto-generated method stub

        if(mmConnectedThread!=null){
            mmConnectedThread.cancel();
            mmConnectedThread = null;
        }

        if(mmConnectThread!=null){
            mmConnectThread.cancel();
            mmConnectThread = null;
        }

        if(mmAcceptThread!=null){
            mmAcceptThread.cancel();
            mmAcceptThread = null;
        }

        setState(STATE_NONE);

    }

    /**
     * Write to the ConnectedThread in an unsynchronized manner
     *
     * @param out
     *            The bytes to write
     * @see ConnectedThread#write(byte[])
     */
    public  void write(byte[] out) {
        // Create temporary object
        ConnectedThread r;
        // Synchronize a copy of the ConnectedThread
        synchronized (this) {
            if (mState != STATE_CONNECTED)
                return;
            r = mmConnectedThread;
        }
        // Perform the write unsynchronized
        //线程调用写入方法
        r.write(out);
    }

    /**
     * failed处理
     * @author micro
     *
     */
    public void connectionFailed(){

        Message msg = mHandler.obtainMessage(BlueToothChat.MESSAGE_TOAST);

        Bundle bundle = new Bundle();
        bundle.putString(BlueToothChat.TOAST, "Device connection failed to connect");
        msg.setData(bundle);

        mHandler.sendMessage(msg);

        //重启对Socket的监听线程,即服务端的线程
        BlueToothChatService.this.start();

    }

    /**
     *
     * @author micro
     *
     */

    public void connectionLost(){

        Message msg = mHandler.obtainMessage(BlueToothChat.MESSAGE_TOAST);

        Bundle bundle = new Bundle();
        bundle.putString(BlueToothChat.TOAST, "Device connection was lost");
        msg.setData(bundle);

        mHandler.sendMessage(msg);

        //重启对Socket的监听线程,即服务端的线程
        BlueToothChatService.this.start();

    }

    //ServerSocket
    private class AcceptThread extends Thread{

        private final BluetoothServerSocket serverSocket;
        private String socketType;

        public AcceptThread(){

            BluetoothServerSocket temp =null;

            try {

                temp = mAdapter.
                        listenUsingRfcommWithServiceRecord(NAME, MY_UUID);

            } catch (Exception e) {
                // TODO: handle exception
                Log.e("listen Thread", "failed to get the temp thread");
            }

            serverSocket = temp;

        }

        @Override
        public void run(){

            setName("AcceptThread" + socketType);

            BluetoothSocket socket = null;

            //如果设备没有连接

            while(mState!=STATE_CONNECTED){

                try {

                    socket = serverSocket.accept();
                    Log.e("success", "success");

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    Log.e("socket", "couldn‘t accept the socket sending");
                    break;
                }

            //如果Socket.accpt()成功
            if(socket!=null){

                //异步线程加载
                synchronized (BlueToothChatService.this) {

                    switch(mState){

                    case STATE_LISTEN:
                    case STATE_CONNECTING:
                        Log.e("connectting or Listen", "start");
                        connected(socket,socket.getRemoteDevice(),socketType);
                        Log.e("connectting or Listen", "success");
                        break;

                    //None或者连接上的时候关闭socket
                    case STATE_NONE:
                    case STATE_CONNECTED:
                        try {
                            socket.close();
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }

                        break;

                    }

                }
            }

            }

        }

        public void cancel(){
            try {
                serverSocket.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    //连接线程connectThread,用于连接

    private class ConnectThread extends Thread{

        private BluetoothSocket mmSocket;
        private BluetoothDevice mmDevice;

        private String mSocketTye;

        public ConnectThread(BluetoothDevice device){

            mmDevice = device;

            BluetoothSocket temp = null;

            try {

                temp = device.createRfcommSocketToServiceRecord(MY_UUID);

            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }

            mmSocket = temp;

        }

        @Override
        public void run(){

            setName("ConnectThread"+mSocketTye);

            //关闭扫描发现,否则会影响socket之间的连接
            mAdapter.cancelDiscovery();

            try {
                Log.e("mmSocket", "mmSocket.connect()");
                mmSocket.connect();
                Log.e("mmSocket", "mmSocket.connect success");

            } catch (Exception e) {
                // TODO: handle exception
                try {
                    mmSocket.close();
                } catch (Exception e2) {
                    // TODO: handle exception

                }
                //连接失败
                connectionFailed();
                return;
            }

            //重置
            synchronized (BlueToothChatService.this) {

                mmConnectThread = null;
            }

            //已连接的线程Start the ConnectedThread to begin managing a Bluetooth connection
            connected(mmSocket,mmDevice,mSocketTye);
        }

        public void cancel(){
            try {
                mmSocket.close();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

    //这是一个在两个设备之间进行数据交换的线程,前提是已经连接上

    private class ConnectedThread extends Thread{

        private  BluetoothSocket mmSocket ;
        private  InputStream mmInput ;
        private  OutputStream mmOuput ;

        public ConnectedThread(BluetoothSocket socket,String socketType){

            mmSocket = socket;

            InputStream tmpInput = null;
            OutputStream tmpOutput = null;

            try {

                tmpInput = socket.getInputStream();
                tmpOutput = socket.getOutputStream();

            } catch (Exception e) {
                // TODO: handle exception
            }

            mmInput = tmpInput;
            mmOuput = tmpOutput;

        }

        @Override
        public void run(){

            byte[]  buff  =  new byte[1024];

            int bytes;

            while (true) {

                try {
                    //读取
                    bytes = mmInput.read(buff);

                    //发送到UI线程处理
                    mHandler.obtainMessage(BlueToothChat.MESSAGE_READ,
                            bytes, -1, buff).sendToTarget();

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    connectionLost();
                    BlueToothChatService.this.start();
                    break;
                }

            }

        }

        //写入
        public void write(byte[] buff){

            try {

                mmOuput.write(buff);

                mHandler.obtainMessage(BlueToothChat.MESSAGE_WRITE,
                        -1, -1, buff).sendToTarget();

            } catch (Exception e) {
                // TODO: handle exception
            }

        }

        public void cancel(){
            try {
                mmSocket.close();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

    }

}

/*关于客户端和服务端:
首先每一部设备都有服务线程和连接线程,当一部设备(A)对另一部设备(B)发起连接的时候,那么A将作为客户端,而B作为服务端,B的服务端线程的serverSocket将不断监听来自客户端的socket
即就是:socket = serverSocket.accept();
这个实现之后,才能实现彼此的聊天数据线程的连接和交换*/

接下来实现的是:

已配对列表和发现新设备的列表和开启300s蓝牙可被发现的功能

/**
 * This Activity appears as a dialog. It lists any paired devices and devices
 * detected in the area after discovery. When a device is chosen by the user,
 * the MAC address of the device is sent back to the parent Activity in the
 * result Intent.
 * 这个活动将以dialog的形式显示,主要通过主题设置实现
 * 包含的功能有:已配对的设备列表和发现的设备列表
 * 当选择任何一个选项的时候,将返回一些信息给BlueToothChat
 *
 */

public class DeviceListActivity extends Activity {

    public static final String EXTRA_DEVICE_ADDRESS = "device_name";

    //蓝牙必备
    private BluetoothAdapter mBtAdapter;
    private ArrayAdapter<String> mPairDeviceArrayAdapter;         //已配对的适配器
    private ArrayAdapter<String> mNewDevicesArrayAdapter;         //发现的新设备适配器

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.device_list);

        Button scanBtn = (Button)findViewById(R.id.button_scan);
        scanBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                //点击之后开始扫描发现,按钮隐藏不可见
                // TODO Auto-generated method stub
                doDiscovery();
                v.setVisibility(View.GONE);

            }
        });

        //初始化适配器
        mPairDeviceArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);

        mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);

        ListView pairedList = (ListView)findViewById(R.id.paired_devices);

        ListView newList   = (ListView)findViewById(R.id.new_devices);

        pairedList.setAdapter(mPairDeviceArrayAdapter);
        newList.setAdapter(mNewDevicesArrayAdapter);

        pairedList.setOnItemClickListener(mDeviceClickListener);
        newList.setOnItemClickListener(mDeviceClickListener);

        //注册广播及状态
        IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(reciver, intentFilter);

        intentFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        this.registerReceiver(reciver, intentFilter);

        //

        mBtAdapter = BluetoothAdapter.getDefaultAdapter();

        Set<BluetoothDevice>  pairedDevices = mBtAdapter.getBondedDevices();

        if(pairedDevices.size()>0){

            findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);

            for(BluetoothDevice device:pairedDevices){
                mPairDeviceArrayAdapter.add(device.getName()+"\n"+device.getAddress());
            }

        }else{

            String noDevice = getResources().getText(R.string.none_paired).toString();

            mPairDeviceArrayAdapter.add(noDevice);
        }

    }

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

        if(mBtAdapter!=null){
            mBtAdapter.cancelDiscovery();
        }

        this.unregisterReceiver(reciver);
    }

    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> av, View v, int arg2,
                long arg3) {
            // TODO Auto-generated method stub
            //停止扫描发现
            mBtAdapter.cancelDiscovery();

            //截取后面17位字符也就是Mac地址
            String info = ((TextView)v).getText().toString();

            String address = info.substring(info.length()-17);

            Intent intent = new Intent();
            intent.putExtra(EXTRA_DEVICE_ADDRESS, address);//返回了一个地址
            setResult(RESULT_OK, intent);

            finish();//关闭界面
        }
    };

    public void doDiscovery() {
        // TODO Auto-generated method stub

        setProgressBarVisibility(true);
        setTitle(R.string.scanning);
        findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);

        if(mBtAdapter.isDiscovering()){
            mBtAdapter.cancelDiscovery();
        }

        mBtAdapter.startDiscovery(); //开始扫描发现

    }

    // The BroadcastReceiver that listens for discovered devices and
    // changes the title when discovery is finished
    //通过广播对扫描的设备做处理

    private final BroadcastReceiver reciver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub

            //获取当前的Action即就是其状态
            String action = intent.getAction();

            //same and then
            if(BluetoothDevice.ACTION_FOUND.equals(action)){

                //获取设备对象
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                //判断该设备是否已配对
                if(device.getBondState()!=BluetoothDevice.BOND_BONDED){

                    mNewDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());

                }

            }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
                //扫描结束
                setProgressBarVisibility(false);
                setTitle(R.string.select_device);

                if(mNewDevicesArrayAdapter.getCount()==0){
                    String noDevice = getResources().getText(R.string.none_found).toString();
                    mNewDevicesArrayAdapter.add(noDevice);
                }
            }

        }
    };

}
权限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

    <uses-permission android:name="android.permission.BLUETOOTH" />

以下是一些布局文件

device_list.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <TextView android:id="@+id/title_paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_paired_devices"
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp"
    />
    <ListView android:id="@+id/paired_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stackFromBottom="true"
        android:layout_weight="1"
    />
    <TextView android:id="@+id/title_new_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/title_other_devices"
        android:visibility="gone"
        android:background="#666"
        android:textColor="#fff"
        android:paddingLeft="5dp"
    />
    <ListView android:id="@+id/new_devices"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:stackFromBottom="true"
        android:layout_weight="2"
    />
    <Button android:id="@+id/button_scan"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_scan"
    />
</LinearLayout>

device_name.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:padding="5dp"
/>

message.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:padding="5dp"
/>

main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/chat_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:stackFromBottom="true"
        android:transcriptMode="alwaysScroll"
        android:layout_weight="1">

    </ListView>

    <LinearLayout
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/edit_text"
            android:layout_height="wrap_content"
            android:layout_width="0dp"
            android:layout_weight="1"
            />

        <Button
            android:id="@+id/send_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/send"/>

    </LinearLayout>

</LinearLayout>

strings.xml:
<resources>

    <string name="app_name">BlueToothChat</string>
    <string name="send">Send</string>
    <string name="not_connected">You are not connected to a device</string>
    <string name="title_connecting">connecting...</string>
    <string name="title_not_connected">not connected</string>

     <string name="bt_not_enabled_leaving">Bluetooth was not enabled. Leaving Bluetooth Chat.</string>

      <!-- Options Menu -->
    <string name="connect">Connect a device</string>
    <string name="discoverable">Make discoverable</string>

    <!--  DeviceListActivity -->
    <string name="scanning">scanning for devices...</string>
    <string name="select_device">select a device to connect</string>
    <string name="none_paired">No devices have been paired</string>
    <string name="none_found">No devices found</string>
    <string name="title_paired_devices">Paired Devices</string>
    <string name="title_other_devices">Other Available Devices</string>
    <string name="button_scan">Scan for devices</string>

</resources>

option_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/connect_scan"
          android:icon="@android:drawable/ic_menu_search"
          android:title="@string/connect"
          android:showAsAction="ifRoom|withText" />
    <item android:id="@+id/discoverable"
          android:icon="@android:drawable/ic_menu_mylocation"
          android:title="@string/discoverable"
          android:showAsAction="ifRoom|withText" />
</menu>

AndroidManifest.xml的Apllication部分:
<application
        android:allowBackup="true"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name=".BlueToothChat"
                  android:configChanges="orientation|keyboardHidden">
            <intent-filter >
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <activity
            android:name="DeviceListActivity"
            android:label="@string/select_device"
            android:theme="@android:style/Theme.Holo.Dialog"
            android:configChanges="orientation|keyboardHidden"></activity>
    </application>
时间: 2024-11-11 04:18:40

蓝牙聊天的相关文章

手把手教你做蓝牙聊天应用(一)-设计方案

前言 通过"计算器"和"视频播放器"我们已经能够开始开发一些比较像样的应用了. 今天,我们将开始制作一个"蓝牙聊天"应用.这个应用其实很简单,没有炫酷的界面,就是一对一.通过蓝牙连接两台设备,让两个人互相发送信息. 可别觉得它太无聊.没有什么实用性,其实我们正是想通过它让你开始接触网络编程(蓝牙和wifi都是无线连接技术,它们的程序设计方法和思路非常的相似). 另外,学会了使用蓝牙,就为大家打开了技术开发的另一扇大门-物联网,现在很多物联网硬件都

开源项目--蓝牙聊天

前言 基于Android Classic Bluetooth的蓝牙聊天软件,目前仅支持一对一实时通信.文件传输.好友添加.好友分组.好友在线状态更新等功能,其中消息发送支持文本.表情等方式. 项目地址:https://github.com/xiaoyaoyou1212/BluetoothChat(欢迎Fork参与) 前景 蓝牙技术作为一种小范围无线连接技术,能够在设备间实现方便快捷.灵活安全.低成本.低功耗的数据和语音通信,是目前实现无线个人局域网的主流技术之一.同时,蓝牙系统以自组式组网的方式

【视频】零基础学Android开发:蓝牙聊天室APP(一)

零基础学Android开发:蓝牙聊天室APP第一讲 1. Android介绍与环境搭建:史上最高效Android入门学习 1.1 Google的大小战略 1.2 物联网与云计算 1.3 智能XX设备 1.4 Android发展前景 1.5 Android企业需求与就业薪资 1.6 Android框架介绍 1.7 搭建Android开发环境 1.8 Android SDK文件夹具体解释 1.9 开发第一个App:HelloWorld 1.10 App应用程序文件夹具体解释 在线收看:http://

【视频】零基础学Android开发:蓝牙聊天室APP(三)

零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件详解 3.2 GridView控件详解 3.3 SimpleAdapter适配器详解 3.4 事件监听器:OnItemClickListener 3.5 输入和显示表情图像 在线收看:http://www.3g-edu.org/news/video023.htm 视频下载:http://pan.baidu.com/s/1kTmiNqf

【视频】零基础学Android开发:蓝牙聊天室APP(四)

零基础学Android开发:蓝牙聊天室APP第四讲 4.1 ListView控件的使用 4.2 BaseAdapter详解 4.3 ListView分布与滚动事件 4.4 ListView事件监听器:OnItemClickedListener 在线收看:http://www.3g-edu.org/news/video026.htm 视频下载:http://pan.baidu.com/s/1jGkjDGE

Android蓝牙聊天程序的扩展开发(基于Google Sample,类QQ设计)

首先看看程序的效果: 在整个开发过程中涉及的几个关键步骤 1)判断蓝牙设备是否可用 2)若蓝牙设备可用,判断是否开启 是:则不操作 否:开启蓝牙设备 3)让设备可见(在一定的时间范围内) 4)查看已经连接过的设备 5)扫描附近的设备 6)连接设备 7)建立socket连接,读写消息 8)退出程序时结束扫描和连接 程序架构: ChatActivity:UI的变化 接收(发送)来自BluetoothChatService的消息,接收         DeviceListActivity的消息 Dev

【视频】零基础学Android开发:蓝牙聊天室APP(二)

零基础学Android开发:蓝牙聊天室APP第二讲 2.1 课程内容应用场景 2.2 Android UI设计 2.3 组件布局:LinearLayout和RelativeLayout 2.4 TextView.EditText.Button控件 2.5 文本信息的隐藏和显示 2.6 输入和显示表情图像 在线收看:http://www.3g-edu.org/news/video022.htm 视频下载:http://pan.baidu.com/s/1mgHoObu

手把手教你做蓝牙聊天应用(六)-界面优化

第6节 应用的美化与完善 现在,我们还可以为聊天应用加上多国语言的支持和关于界面,把使用到的颜色和尺寸定义到资源文件当中,这样一来,安豆的蓝牙聊天应用就算是比较完整的完成了. 这两部分在以前"计算器"章节中,已经介绍过了,大家就自己动手吧. 这一节,我们将重点介绍聊天文字的背景图片是如何制作的. 6.1 9Patch图片的原理 观察一下安卓系统中需要经常用到的图片,可以发现: 很多要使用透明效果的地方在转角处: 很多图片不同的地方只在靠近边缘的地方,内部区域几乎都是一样的: 为此安卓系

手把手教你做蓝牙聊天应用(三)-获取要连接的设备

第3节 获取要连接的设备 这一节我们开始设计蓝牙聊天应用的界面.根据之前的规划,连接管理将放在单独的ConnectionManager模块当中,所以每当要使用连接功能的时候,我们就暂时把它空着,等到ConnectionManager开发完成之后再加进来. 这里我们将完成下面的界面设计, 3.1 主界面 主界面是一个独立的Activity-ChatActivity,它要实现三个主要功能, 当蓝牙没有开启或者设备不能被发现的时候,请求用户打开对应的功能: 下方有输入框输入要发送的文字内容,点击按钮后

手把手教你做蓝牙聊天应用(五)-界面使用ConnectionManager

第5节 界面使用ConnectionManager ConnectionManager已经设计完成了,它的价值需要在ChatActivity中体现出来. 5.1 监听ConnectionManager 实现对ConnectionManager各个状态的监听,当ConnectionManager的状态有变化.收到发送的数据时,需要让ChatActivity知道,它才能将各种变化反应到用户界面上. 5.1.1 创建监听器 ConnectionManager定义了ConnectionListener接