Android学习笔记之蓝牙通信...

PS:最近同学问我蓝牙的事,因此自己也就脑补了一下蓝牙...

 

学习内容:

1.如何实现蓝牙通信技术...

 

  蓝牙通信其实是手机里很常用的一种通信方式,现在的手机中是必然存在蓝牙的,蓝牙通信也是有一部分优点的,功耗低,安全性比较高,但是缺点想必大家都知道,传输的速率也确实是不快,相比于Wifi通信,确实不值一提...虽然影响范围并不高,但是既然蓝牙存在,那么还是有必要知道蓝牙是如何进行通信的...蓝牙通信有两种方式,最常用的就是使用socket套接字来实现蓝牙通信...

  蓝牙通信原理:蓝牙通信的原理很简单,一个设备作为服务端,另一个设备作为客户端,服务端对外暴露,客户端通过发送连接请求,服务端进行响应,然后返回一个BluetoothSocket套接字来管理这个连接...那么服务端个客户端就会共享一个RFCOMM端口,进行数据传递...听起来其实蛮简单的,实现过程还是有点复杂的...这里我还是直接上一个代码吧...

  这个是Activity.java文件...这是个非常长的代码块,看完谁都头痛...我们还是进行分块解释...先把这些代码都略过...还是看最下面的解释...

package com.qualcomm.bluetoothclient;



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.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.inputmethod.InputMethodManager;

import android.widget.AdapterView;

import android.widget.AdapterView.OnItemClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.Toast;

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;



public class ClientActivity extends Activity implements OnItemClickListener {



    private Context mContext;

    private BluetoothAdapter mBluetoothAdapter; // Bluetooth适配器

    private BluetoothDevice device;             // 蓝牙设备

    private ListView mListView;

    private ArrayList<ChatMessage> list;

    private ClientAdapter clientAdapter;        // ListView适配器

    private Button disconnect = null, sendButton = null;

    private EditText editText = null;

    

    private BluetoothSocket socket;     // 客户端socket

    private ClientThread mClientThread; // 客户端运行线程

    private ReadThread mReadThread;     // 读取流线程

    

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        

        init();

    }



    // 变量初始化

    private void init() {

        // TODO Auto-generated method stub

        mContext = this;

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//获取本地蓝牙...

        

        list = new ArrayList<ChatMessage>();// 初始化list

        clientAdapter = new ClientAdapter(mContext, list);  //适配器,用来限制如何显示ListView...

        mListView = (ListView) findViewById(R.id.list);

        

        mListView.setFastScrollEnabled(true);

        

        mListView.setAdapter(clientAdapter);

        

        mListView.setOnItemClickListener(this);

        

        // 注册receiver监听,注册广播...

        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

        registerReceiver(mReceiver, filter);

        

        // 获取已经配对过的蓝牙设备

        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();//获取发现的蓝牙设备的基本信息...

        

        if (pairedDevices.size() > 0) {  

            for (BluetoothDevice device : pairedDevices) {

                //将手机名字和物理地址放入到listview中...

                list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

                

                clientAdapter.notifyDataSetChanged();  //重新绘制ListView

                

                mListView.setSelection(list.size() - 1);

            }

        } else {

            list.add(new ChatMessage("没有已经配对过的设备", true));

            clientAdapter.notifyDataSetChanged();

            mListView.setSelection(list.size() - 1);

        }

        

        editText = (EditText) findViewById(R.id.edit);

        editText.setEnabled(false);

        editText.clearFocus();

        

        sendButton = (Button) findViewById(R.id.btn_send);

        sendButton.setEnabled(false);

        sendButton.setOnClickListener(new OnClickListener() {

            

            @Override

            public void onClick(View arg0) {

                // TODO Auto-generated method stub

                String msg = editText.getText().toString();

                if (msg.length() > 0) {

                    sendMessageHandler(msg);

                    editText.setText("");

                    editText.clearFocus();

                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定义一个输入法对象...通过Context.INPUT_METHOD_SERVICE获取实例...

                    //当EditText没有焦点的时候,阻止输入法的弹出...其实就是在没点击EditText获取焦点的时候,没有输入法的显示...

                    imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);

                } else {

                    Toast.makeText(mContext, "发送内容不能为空", Toast.LENGTH_SHORT).show();

                }

            }

        });

        

        disconnect = (Button) findViewById(R.id.disconnect);

        disconnect.setEnabled(false);

        disconnect.setOnClickListener(new OnClickListener() {

            

            @Override

            public void onClick(View arg0) {

                // TODO Auto-generated method stub

                // 关闭相关服务

                closeClient();

                BluetoothMsg.isOpen = false;

                

                BluetoothMsg.serviceOrCilent = BluetoothMsg.ServerOrCilent.NONE;

                Toast.makeText(mContext, "连接已断开", Toast.LENGTH_SHORT).show();

            }

        });

    }

    

    @Override

    protected void onStart() {

        // TODO Auto-generated method stub

        super.onStart();

        if (mBluetoothAdapter != null) {  //本地蓝牙存在...

            if (!mBluetoothAdapter.isEnabled()) {   //判断蓝牙是否被打开...

                // 发送打开蓝牙的意图,系统会弹出一个提示对话框

                Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

                startActivityForResult(enableIntent, RESULT_FIRST_USER);

                

                // 设置蓝牙的可见性,最大值3600秒,默认120秒,0表示永远可见(作为客户端,可见性可以不设置,服务端必须要设置)

                

                //打开本机的蓝牙功能,持续的时间是永远可见...

                Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

                displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);

                startActivity(displayIntent);

                

                // 直接打开蓝牙

                mBluetoothAdapter.enable();

            }

        }

    }

    

    @Override

    protected void onResume() {

        // TODO Auto-generated method stub

        super.onResume();

        // 扫描

        scanDevice();

    }

    

    /**

     * 蓝牙设备扫描过程中(mBluetoothAdapter.startDiscovery())会发出的消息

     * ACTION_FOUND 扫描到远程设备

     * ACTION_DISCOVERY_FINISHED 扫描结束

     */

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override

        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

                // 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                

                // If it's already paired, skip it, because it's been listed already

                // 如果这个设备是不曾配对过的,添加到list列表

                if (device.getBondState() != BluetoothDevice.BOND_BONDED) 

                {

                    list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), false));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

                }

            // When discovery is finished, change the Activity title

            } 

            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) 

            {

                setProgressBarIndeterminateVisibility(false);

                if (mListView.getCount() == 0) 

                {

                    list.add(new ChatMessage("没有发现蓝牙设备", false));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

                }

            }

        }

    };

    

    // Handler更新UI

    private Handler LinkDetectedHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            //Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show();

            if(msg.what==1)

            {

                list.add(new ChatMessage((String)msg.obj, true));

            }

            else

            {

                list.add(new ChatMessage((String)msg.obj, false));

            }

            clientAdapter.notifyDataSetChanged();

            mListView.setSelection(list.size() - 1);

            

        }

        

    };

    

    // 当连接上服务器的时候才可以选择发送数据和断开连接

    private Handler refreshUI = new Handler() {

        public void handleMessage(Message msg) {

            if (msg.what == 0) {

                disconnect.setEnabled(true);

                sendButton.setEnabled(true);

                editText.setEnabled(true);

            }

        }

    };

    

    // 开启客户端连接服务端

    private class ClientThread extends Thread {

        @Override

        public void run() {

            // TODO Auto-generated method stub

            if (device != null) {

                try {

                    socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

                    // 连接

                    Message msg = new Message();

                    msg.obj = "请稍候,正在连接服务器: "+ BluetoothMsg.BlueToothAddress;

                    msg.what = 0;

                    LinkDetectedHandler.sendMessage(msg);

                    

                    // 通过socket连接服务器,这是一个阻塞过程,直到连接建立或者连接失效

                    socket.connect();

                    

                    Message msg2 = new Message();

                    msg2.obj = "已经连接上服务端!可以发送信息";

                    msg2.what = 0;

                    LinkDetectedHandler.sendMessage(msg2);

                    

                    // 更新UI界面

                    Message uiMessage = new Message();

                    uiMessage.what = 0;

                    refreshUI.sendMessage(uiMessage);

                    

                    // 可以开启读数据线程

                    mReadThread = new ReadThread();

                    mReadThread.start();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    // socket.connect()连接失效

                    Message msg = new Message();

                    msg.obj = "连接服务端异常!断开连接重新试一试。";

                    msg.what = 0;

                    LinkDetectedHandler.sendMessage(msg);

                }

            }

        }

    }

    

    // 通过socket获取InputStream流

    private class ReadThread extends Thread {

        @Override

        public void run() {

            // TODO Auto-generated method stub

            byte[] buffer = new byte[1024];

            int bytes;

            InputStream is = null;

            try {

                is = socket.getInputStream();

            } catch (IOException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            while(true) {

                try {

                    if ((bytes = is.read(buffer)) > 0) {

                        byte[] data = new byte[bytes];

                        for (int i = 0; i < data.length; i++) {

                            data[i] = buffer[i];

                        }

                        String s = new String(data);

                        Message msg = new Message();

                        msg.obj = s;

                        msg.what = 1;

                        LinkDetectedHandler.sendMessage(msg);

                    }

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    try {

                        is.close();

                    } catch (IOException e1) {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                    }

                    break;

                }

            }

        }

    }

    

    // 发送数据

    private void sendMessageHandler(String msg) {

        if (socket == null) {

            Toast.makeText(mContext, "没有可用的连接", Toast.LENGTH_SHORT).show();

            return;

        }

        //如果连接上了,那么获取输出流...

        try {

            OutputStream os = socket.getOutputStream();

            os.write(msg.getBytes());

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        list.add(new ChatMessage(msg, false));  //将数据存放到list中

        clientAdapter.notifyDataSetChanged();

        mListView.setSelection(list.size() - 1);

    }

    

    // 停止服务

    private void closeClient() {

        new Thread() {

            public void run() {

                if (mClientThread != null) {

                    mClientThread.interrupt();

                    mClientThread = null;

                }

                if (mReadThread != null) {

                    mReadThread.interrupt();

                    mReadThread = null;

                }

                try {

                    if (socket != null) {

                        socket.close();

                        socket = null;

                    }

                } catch (IOException e) {

                    // TODO: handle exception

                }

            }

        }.start();

    }

    

    // 扫描设备

    private void scanDevice() {

        // TODO Auto-generated method stub

        if (mBluetoothAdapter.isDiscovering()) {  //如果正在处于扫描过程...

            mBluetoothAdapter.cancelDiscovery();  //取消扫描...

        } else {

            list.clear();

            clientAdapter.notifyDataSetChanged();

            

            // 每次扫描前都先判断一下是否存在已经配对过的设备

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

            if (pairedDevices.size() > 0) {

                    for (BluetoothDevice device : pairedDevices) {

                        list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

                        clientAdapter.notifyDataSetChanged();

                        mListView.setSelection(list.size() - 1);

                    }

            } else {

                    list.add(new ChatMessage("No devices have been paired", true));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

              }                

            /* 开始搜索 */

            mBluetoothAdapter.startDiscovery();

        }

    }



    @Override

    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

        // TODO Auto-generated method stub

        ChatMessage item = list.get(arg2);  //item保存着message和一个boolean数值...

        String info = item.getMessage();    //单纯获取message的信息...

        

        String address = info.substring(info.length() - 17);//获取MAC地址...其实就是硬件地址...

        

        

        BluetoothMsg.BlueToothAddress = address;

        

        // 停止扫描

        // BluetoothAdapter.startDiscovery()很耗资源,在尝试配对前必须中止它

        mBluetoothAdapter.cancelDiscovery();

        

        // 通过Mac地址去尝试连接一个设备

        device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress);

        mClientThread = new ClientThread();  //开启新的线程...

        mClientThread.start();

        BluetoothMsg.isOpen = true;

        

    }



    @Override

    protected void onDestroy() {

        // TODO Auto-generated method stub

        super.onDestroy();

        if (mBluetoothAdapter != null) {

            mBluetoothAdapter.cancelDiscovery();

            // 关闭蓝牙

            mBluetoothAdapter.disable();

        }

        unregisterReceiver(mReceiver);

        closeClient();

    }

}
View Code

   这个是我自定义了一个类,用来判断蓝牙的连接类型...

package com.qualcomm.bluetoothclient;



public class BluetoothMsg {



    /** 

     * 蓝牙连接类型  

     * 

     */  

    public enum ServerOrCilent {

        NONE,  

        SERVICE,  

        CILENT  

    };

    

    //蓝牙连接方式  

    public static ServerOrCilent serviceOrCilent = ServerOrCilent.NONE;  

    //连接蓝牙地址  

    public static String BlueToothAddress = null, lastblueToothAddress = null;  

    //通信线程是否开启  

    public static boolean isOpen = false;

    

}

  这个是保存我们发送的数据信息的自定义类...

package com.qualcomm.bluetoothclient;

/*

 *  这里定义一个类,用来保存我们发送的数据信息...

 * 

 */

public class ChatMessage {



    private String message;

    private boolean isSiri;

    

    public ChatMessage(String message, boolean siri) {

        // TODO Auto-generated constructor stub

        this.message = message;

        this.isSiri = siri;

    }



    public String getMessage() {

        return message;

    }



    public void setMessage(String message) {

        this.message = message;

    }



    public boolean isSiri() {

        return isSiri;

    }



    public void setSiri(boolean isSiri) {

        this.isSiri = isSiri;

    }

    

    

}

  最后这个是适配器...因为我这里使用到了ListView,因此我需要使用一个适配器来设置ListView以何种方式显示在屏幕上...

package com.qualcomm.bluetoothclient;



import java.util.ArrayList;



import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.TextView;



/*

 * 

 * 

 * 

 * 

 * 

 */

public class ClientAdapter extends BaseAdapter {



    private ArrayList<ChatMessage> list;

    private LayoutInflater mInflater;

    

    public ClientAdapter(Context context, ArrayList<ChatMessage> messages) {

        // TODO Auto-generated constructor stub

        this.list = messages;

        this.mInflater = LayoutInflater.from(context);

    }

    

    @Override

    public int getCount() {

        // TODO Auto-generated method stub

        return list.size();

    }



    @Override

    public Object getItem(int position) {

        // TODO Auto-generated method stub

        return list.get(position);

    }



    @Override

    public long getItemId(int position) {

        // TODO Auto-generated method stub

        return position;

    }

    

    @Override

    public int getItemViewType(int position) {

        // TODO Auto-generated method stub

        return position;

    }



    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        // TODO Auto-generated method stub

        ViewHolder viewHolder = null;

        ChatMessage message = list.get(position);

        if (convertView == null) {

            convertView = mInflater.inflate(R.layout.list_item, null);

            viewHolder = new ViewHolder((View)convertView.findViewById(R.id.list_child)

                    , (TextView)convertView.findViewById(R.id.chat_msg));

            convertView.setTag(viewHolder);

        } else {

            viewHolder = (ViewHolder) convertView.getTag();

        }

        if (message.isSiri()) {

            viewHolder.child.setBackgroundResource(R.drawable.msgbox_rec);

        } else {

            viewHolder.child.setBackgroundResource(R.drawable.msgbox_send);

        }

        viewHolder.msg.setText(message.getMessage());

        

        return convertView;

    }



    class ViewHolder {

          protected View child;

        protected TextView msg;



        public ViewHolder(View child, TextView msg){

            this.child = child;

            this.msg = msg;

            

        }

    }



}

  在这里我进行正式的解释...先说第二部分..第二部分是一些初始化的操作...也就是获取本地蓝牙,注册广播,设置监听的一些过程...因为实现通信,我们首先要判断我们的手机是否有蓝牙...获取到本机的蓝牙... 也就是这句话是实现通信的第一步...mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();我们才能够打开蓝牙...然后进行操作...详细解释在代码中...

    //→_→ 第二部分...

    

    // 变量初始化

    private void init() {

        // TODO Auto-generated method stub

        mContext = this;

        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//获取本地蓝牙...实现通信的第一步...

        

        list = new ArrayList<ChatMessage>();// 初始化list,由于我们最后会将数据以列表的形式进行显示,因此使用ListView...

        clientAdapter = new ClientAdapter(mContext, list);  //适配器,用来限制如何显示ListView...

        

        mListView = (ListView) findViewById(R.id.list);

        

        mListView.setFastScrollEnabled(true);  //使用快速滑动功能..目的是能够快速滑动到指定位置...

        

        mListView.setAdapter(clientAdapter);

        

        mListView.setOnItemClickListener(this);

        

        /* 下面是注册receiver监听,注册广播...说一下为什么要注册广播...

         * 因为蓝牙的通信,需要进行设备的搜索,搜索到设备后我们才能够实现连接..如果没有搜索,那还谈什么连接...

         * 因此我们需要搜索,搜索的过程中系统会自动发出三个广播...这三个广播为:

         * ACTION_DISCOVERY_START:开始搜索...

         * ACTION_DISCOVERY_FINISH:搜索结束...

         * ACTION_FOUND:正在搜索...一共三个过程...因为我们需要对这三个响应过程进行接收,然后实现一些功能,因此

         * 我们需要对广播进行注册...知道广播的人应该都知道,想要对广播进行接收,必须进行注册,否则是接收不到的...

         * */

        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

        registerReceiver(mReceiver, filter);

        

        // 定义一个集合,来保存已经配对过的设备...

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

        

        if (pairedDevices.size() > 0) {  //如果存在设备...

            for (BluetoothDevice device : pairedDevices) {//遍历...

                

                //将手机名字和物理地址放入到listview中...

                list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

                

                clientAdapter.notifyDataSetChanged();  //重新绘制ListView

                

                mListView.setSelection(list.size() - 1); //设置list保存的信息的位置...说白了该条信息始终在上一条信息的下方...

            }

        } else {  

            list.add(new ChatMessage("没有已经配对过的设备", true));

            clientAdapter.notifyDataSetChanged();

            mListView.setSelection(list.size() - 1);

        }

        

        editText = (EditText) findViewById(R.id.edit);

        editText.setEnabled(false);  

        editText.clearFocus();  //设置没有焦点..也就是无法输入任何文字...

        

        sendButton = (Button) findViewById(R.id.btn_send);

        sendButton.setEnabled(false);



        sendButton.setOnClickListener(new OnClickListener() {//设置监听,只有获取到焦点后才能进行此过程...

            

            @Override

            public void onClick(View arg0) {

                // TODO Auto-generated method stub

                String msg = editText.getText().toString();

                

                if (msg.length() > 0) {

                    //调用第五部分线程,通过线程发送我们输入的文本...

                    sendMessageHandler(msg);

                    //发送完清空...

                    editText.setText("");

                    editText.clearFocus();

                    

                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定义一个输入法对象...通过Context.INPUT_METHOD_SERVICE获取实例...

                    //当EditText没有焦点的时候,阻止输入法的弹出...其实就是在没点击EditText获取焦点的时候,没有输入法的显示...

                    imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);

                } else {

                    Toast.makeText(mContext, "发送内容不能为空", Toast.LENGTH_SHORT).show();

                }

            }

        });

        

        disconnect = (Button) findViewById(R.id.disconnect);

        disconnect.setEnabled(false);

        //为断开连接设置监听...

        disconnect.setOnClickListener(new OnClickListener() {

            

            @Override

            public void onClick(View arg0) {

                // TODO Auto-generated method stub

                

                // 关闭相关服务,调用第六部分的函数...

                closeClient();

                //表示蓝牙状态需要关闭...

                BluetoothMsg.isOpen = false;

                

                BluetoothMsg.serviceOrCilent = BluetoothMsg.ServerOrCilent.NONE;

                Toast.makeText(mContext, "连接已断开", Toast.LENGTH_SHORT).show();

            }

        });

    }

  接着就是第三部分了...我们获取到了本地的蓝牙设备,我们就需要把蓝牙进行打开了..只有开启了蓝牙,才能够进行搜索,连接等操作..因此这一步是实现蓝牙通信的关键...

//→_→ 第三部分...

    @Override

    protected void onStart() {

        // TODO Auto-generated method stub

        super.onStart();

        if (mBluetoothAdapter != null) {  //本地蓝牙存在...

            if (!mBluetoothAdapter.isEnabled()) {   //判断蓝牙是否被打开...

                

                // 发送打开蓝牙的意图,系统会弹出一个提示对话框,打开蓝牙是需要传递intent的...

                // intent这个重要的东西,大家应该都知道,它能够实现应用之间通信和交互....

                Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

                //打开本机的蓝牙功能...使用startActivityForResult()方法...这里我们开启的这个Activity是需要它返回执行结果给主Activity的...

                startActivityForResult(enableIntent, RESULT_FIRST_USER);

                

                        

                Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

                // 设置蓝牙的可见性,最大值3600秒,默认120秒,0表示永远可见(作为客户端,可见性可以不设置,服务端必须要设置)

                displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);

                //这里只需要开启另一个activity,让其一直显示蓝牙...没必要把信息返回..因此调用startActivity()

                startActivity(displayIntent);

                

                // 直接打开蓝牙

                mBluetoothAdapter.enable();//这步才是真正打开蓝牙的部分....

            }

        }

    }

    

    //这步就是当线程从Pause状态到Avtive状态要执行的过程...

    @Override

    protected void onResume() {

        // TODO Auto-generated method stub

        super.onResume();

        // 扫描

        scanDevice();  //调用第七部分的扫描过程...

    }

  然后是第四部分....第四部分是对广播响应后的接收过程..这个过程也是重要的,因为我们在开启蓝牙后扫描的时候,如果有设备可以连接,我们得做一些操作让用户知道有设备可以连接,总不能有设备连接,我们什么也不告诉用户,这就不合理吧....因此我们在这一步是需要给用户反馈信息的...让用户知道下一步应该做什么...这一部分倒是很简单,没复杂的东西..

//→_→ 第四部分...

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

          

            String action = intent.getAction(); //获取当前正在执行的动作...





            if (BluetoothDevice.ACTION_FOUND.equals(action)) //正在搜索过程...

            {

                // 通过EXTRA_DEVICE附加域来得到一个BluetoothDevice设备

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                

                // 如果这个设备是不曾配对过的,添加到list列表

                if (device.getBondState() != BluetoothDevice.BOND_BONDED) 

                {

                    list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), false));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

                }

            } 

            else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) //搜索结束后的过程...

            {

                setProgressBarIndeterminateVisibility(false);  //这步是如果设备过多是否显示滚动条...

                if (mListView.getCount() == 0) 

                {

                    list.add(new ChatMessage("没有发现蓝牙设备", false));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

                }

            }

        }

    };

  第五部分就是线程部分了,所有的线程部分...涉及UI的更新,数据信息的显示,将数据进行发送,接收服务器返回的数据信息...这步是实现数据传递的关键...

   //→_→ 第五部分...

    

    private Handler LinkDetectedHandler = new Handler() {

        @Override

        public void handleMessage(Message msg) {

            //这步多了一个判断..判断的是ListView保存的数据是我们要传输给服务端的数据,还是那些我们定义好的提示数据...

            if(msg.what==1)

            {

                list.add(new ChatMessage((String)msg.obj, true));

            }

            else

            {

                list.add(new ChatMessage((String)msg.obj, false));

            }

            clientAdapter.notifyDataSetChanged();

            mListView.setSelection(list.size() - 1);

            

        }

        

    };

    // Handler更新UI...

    // 当连接上服务器的时候才可以选择发送数据和断开连接,并且要对界面进行刷新操作...

    private Handler refreshUI = new Handler() {

        public void handleMessage(Message msg) {

            if (msg.what == 0) {

                disconnect.setEnabled(true);

                sendButton.setEnabled(true);

                editText.setEnabled(true);

            }

        }

    };

    

    // 开启客户端连接服务端,一个新的线程...

    private class ClientThread extends Thread {

        @Override

        public void run() {

            // TODO Auto-generated method stub

            if (device != null) {

                try {

                    /* 下面这步也是关键,我们如果想要连接服务器,我们需要调用方法createRfcommSocketToServiceRecord

                     * 参数00001101-0000-1000-8000-00805F9B34FB表示的是默认的蓝牙串口...通过传递参数调用方法,

                     * 会返回给我们一个套接字..这一步就是获取套接字,实现连接的过程...

                     * 

                     * */

                    socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

                    // 连接

                    Message msg = new Message();

                    msg.obj = "请稍候,正在连接服务器: "+ BluetoothMsg.BlueToothAddress;

                    msg.what = 0;

                    LinkDetectedHandler.sendMessage(msg); //调用线程,显示msg信息...

                    

                    // 通过socket连接服务器,正式形成连接...这是一个阻塞过程,直到连接建立或者连接失效...

                    socket.connect();

                    //如果实现了连接,那么服务端和客户端就共享一个RFFCOMM信道...

                    Message msg2 = new Message();

                    msg2.obj = "已经连接上服务端!可以发送信息";

                    msg2.what = 0;

                    LinkDetectedHandler.sendMessage(msg2); //调用线程,显示msg信息...

                    

                    // 如果连接成功了...这步就会执行...更新UI界面...否则走catch(IOException e)

                    Message uiMessage = new Message();

                    uiMessage.what = 0;

                    refreshUI.sendMessage(uiMessage);

                    

                    // 可以开启读数据线程

                    mReadThread = new ReadThread();

                    mReadThread.start();

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    // socket.connect()连接失效

                    Message msg = new Message();

                    msg.obj = "连接服务端异常!断开连接重新试一试。";

                    msg.what = 0;

                    LinkDetectedHandler.sendMessage(msg);

                }

            }

        }

    }

    

    // 通过socket获取InputStream流..

    private class ReadThread extends Thread {

        @Override

        public void run() {

            // TODO Auto-generated method stub

    

            byte[] buffer = new byte[1024];

            int bytes;

            InputStream is = null;

            try {

                is = socket.getInputStream(); //获取服务器发过来的所有字节...

            } catch (IOException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

            while(true) {

                try {//读取过程,将数据信息保存在ListView中...

                    if ((bytes = is.read(buffer)) > 0) {

                        byte[] data = new byte[bytes];

                        for (int i = 0; i < data.length; i++) {

                            data[i] = buffer[i];

                        }

                        String s = new String(data);

                        Message msg = new Message();

                        msg.obj = s;

                        msg.what = 1;  //这里的meg.what=1...表示的是服务器发送过来的数据信息..

                        LinkDetectedHandler.sendMessage(msg);

                    }

                } catch (IOException e) {

                    // TODO Auto-generated catch block

                    try {

                        is.close();

                    } catch (IOException e1) {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                    }

                    break;

                }

            }

        }

    }

    //这一步表示的是发送数据的过程...

    private void sendMessageHandler(String msg) {

        if (socket == null) {

            Toast.makeText(mContext, "没有可用的连接", Toast.LENGTH_SHORT).show();

            return;

        }

        //如果连接上了,那么获取输出流...

        try {

            OutputStream os = socket.getOutputStream();

            os.write(msg.getBytes());//获取所有的自己然后往外发送...

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        list.add(new ChatMessage(msg, false));  //将数据存放到list中

        clientAdapter.notifyDataSetChanged();

        mListView.setSelection(list.size() - 1);

    }

  第六部分就是一个停止服务的一个过程,就不细说了,第七部分就是一个扫描的过程,扫描附近的设别...

 // →_→ 第七部分...

    // 扫描设备

    private void scanDevice() {

        // TODO Auto-generated method stub

        if (mBluetoothAdapter.isDiscovering()) {  //如果正在处于扫描过程...

            mBluetoothAdapter.cancelDiscovery();  //取消扫描...

        } else {

            list.clear();  

            clientAdapter.notifyDataSetChanged();

            

            // 每次扫描前都先判断一下是否存在已经配对过的设备

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

            if (pairedDevices.size() > 0) {  //如果存在配对过的设备,那么就直接遍历集合,然后显示..

                    for (BluetoothDevice device : pairedDevices) {

                        list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true));

                        clientAdapter.notifyDataSetChanged();

                        mListView.setSelection(list.size() - 1);

                    }

            } else {  //如果没有就进行添加...

                    list.add(new ChatMessage("No devices have been paired", true));

                    clientAdapter.notifyDataSetChanged();

                    mListView.setSelection(list.size() - 1);

              }                

            /* 开始搜索 */

            mBluetoothAdapter.startDiscovery();

        }

    }

  第八部分为连接过程做了一些初始化的工作,获取其他设备的物理地址,通过物理地址实现连接...至于第九部分就是销过程了,第一部分就是变量的定义过程...就没什么好说的了...

 //→_→  第八部分...

    @Override

    public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {

        // TODO Auto-generated method stub

        ChatMessage item = list.get(arg2);  //item保存着message和一个boolean数值...

        String info = item.getMessage();    //单纯获取message的信息...

        

        String address = info.substring(info.length() - 17);//获取MAC地址...其实就是硬件地址...因为连接设别必然从物理地址下手...

        

        

        BluetoothMsg.BlueToothAddress = address;//赋值

        

        // 停止扫描

        // BluetoothAdapter.startDiscovery()很耗资源,在尝试配对前必须中止它

        mBluetoothAdapter.cancelDiscovery();

        

        // 通过Mac地址去尝试连接一个设备,

        device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress);

        

        mClientThread = new ClientThread();  

        mClientThread.start();   //开启新的线程...开始连接...这里只是做了一些初始化的工作..连接过程还是ClientThread线程...

        BluetoothMsg.isOpen = true;

        

    }

xml文件我就不贴了,直接放一个源码吧...这个源码包含一个客户端,一个服务端...(注意,这个测试需要在两个真机上测试,模拟器是没有作用的...)

源码地址:http://files.cnblogs.com/files/RGogoing/Bluetooth.zip

 

你可能感兴趣的:(Android学习)