BluetoothChat

      本来想自己写一个蓝牙聊天的程序的,可是看了好几天官方提供的源码,真的看得想哭,真的太蛋筒了,终于明白,基础差,在做稍微复杂写的程序的时候,就能看出自己的不足,就有瓶颈。从这个蓝牙开发来说,可以说是我做这个Android以来遇到的第一个比较头痛的问题,但是由于项目要用到蓝牙,所以这些天只能硬着皮头看下去,不得不说,越看,学到的东西越多,但是我也不能一一说出来,但是,不得不说,任然还有不懂的地方。尤其是多线程那一块,一定要重新认真看。不得不说,这个程序,给我了很大的刺激,让我明白,我还有太多要学习的。

       我这里把我这几天看的,然后今天整理的官方的程序写上了我自己的注释,不是很多,但是最主要的是,我把程序的部分调序了,因为我觉得这是一个理解问题,就是按照什么样的顺序和思路来设计程序的。这样调序,可以很方便理解。但是,我不能保证我的理解思路就是适合别人的,但是至少适合我。还有就是service里面的几个线程的程序,我没有注释,因为真的不知道怎么注释比较好,不想直接翻译他提供的英语。

       我依次说下他这三个代码的思路吧,我觉得第一个DeviceListActivity这个是最容易理解的,也是思路最明确的,内容也最少。大的方面就是两点,一个是显示本地已配对设备;二是显示搜索到的设备。先说第一个,显示本地已配对设备就直接通过一个set集合把pairedDevices遍历一遍,然后显示在listview里面。第二个稍微复杂点,因为要先查找,然后再显示出来。查找直接用startDiscovery就可以了。至于显示就比较麻烦,因为查找的过程是查找一个就发送一个广播,然后继续查找,直到查找结束。这就有一个问题,怎么把查找到一个就显示出一个呢?这就要用到BroadcastReceiver,这里要设置两个过滤器,用来处理不同的广播,一个是用来处理查找到新设备的广播,一个是用来处理结束查找的广播。第一个广播是最重要的,就是查到一个,通过这个过滤器,然后如果是这个广播,就执行显示操作。不过这里显示有两部分,一个是显示name,一个是MAC地址。不过这还么有完,因为你只是显示在listview里面了,但是你还要设置listview的选项监听器,因为我们要能选择一个设备,然后就进行和设备的配对,至于怎么配对待会再说,这里要能响应,然后把MAC地址返回到BluetoothChat这个activity里面,然后执行配对。所以这里使用的是setResult,把Intent的内容传回到主activity。这就是这个DeviceListActivity的全部功能。

        接下来说BluetoothChat这个activity。总的来说是一下几个步骤,检测蓝牙,蓝牙是否打开,蓝牙的可被检测性,建立连接,开始聊天服务,但是有一个是贯穿整个流程的,就是UI的动态更新。蓝牙的检测和打开,可被检测这都很简单,不多说了。主要是怎么建立连接,这个要在service里面说;这个activity最最主要的有两点,一个是把信息显示在在listview上,就是发送和接收到的信息都要显示出来,这个其实也是在service的connectedThread里面做的,但是显示部分是在这个里面,service里只是通过handler把信息传给这个activity,BluetoothChat这个activity只是负责显示。另外一点就是连接状态的显示,分为四个状态,没有操作,连接中,连接了,和接收监听,我这个翻译也许不准确,但是应该能理解这四个状态,不过你从显示上看,只能看到三个,而监听这个是看不出来的。这四个状态也是通过handler传递信息,然后显示在状态栏的。其实这里面最难的就是这个handler的使用,因为他有两个功能,就是上面两类信息的显示。而第二类的显示就是所谓的UI的更新,也就是界面里能看到的动态listview和textview的显示。不过我也不能一下子说清楚这个handler,(我也还在学习中),所以希望我们都能好好学习,嘻嘻。。。

        最后要说的就是这个service,也是最复杂的部分,其实这部分之所以复杂,主要是用到多线程,因为,这里面的很多方法都是阻塞线程的。大体上来说,我也只是说我知道的,这个服务,就是建立连接,那么中间有那些可能性呢?connect,connectionFailed,connected,connectionLost。而这四种可能性我想大家也都可以有自己的理解,我的理解就是,第一个是连接两个设备,第二个是连接失败,第三个是连接成功了,第四个也是连接失败,不过这个和第二个的区别在于,这个的前一状态是第三个,而不是第一个。由这四个引出的是两个线程,也是最重要的线程,ConnectThread和ConnectedThread,第一个是用来建立连接的,第二个是已经连接了,处理的是连接中的事,主要是两点,一个是收发信息,一个是如果发生connectionLost怎么办。而第一个建立连接是通过createRfcommSocketToServiceRecord方法来实现的。但是我们前面说到了这里有三个线程,还有一个是AcceptThread,这是一个监听socket的线程,用来查看有没有连接请求,我对他的理解是,他要监听的是刚才连接时说到的那个方法的UUID,然后进行连接。然后返回的是一个socket。这里还有的就是UI的更新,这里用到的是state的设置,然后通过handler把这个state返回去,然后更新UI。

        好吧,这就是我能理解的部分,还有就是把我的注释的给展示出来吧。至于以后用到蓝牙的部分,以后再更新吧。

        这是这个月最后一更了,这个月本来这应该是最有价值的一篇文章,结果,水平太菜了,没办法,只能做到这里,五一回家玩玩吧,放松下。。。

DeviceListActivity.java

package com.example.bluetooth;

import java.util.Set;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;

public class DeviceListActivity extends Activity {

	private BluetoothAdapter mBtAdapter;
    private ArrayAdapter<String> mPairedDevicesArrayAdapter;
    private ArrayAdapter<String> mNewDevicesArrayAdapter;
    public static String EXTRA_DEVICE_ADDRESS = "device_address";
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		
		//这里设置窗体为不确定进度,因为有progressbar
		requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        setContentView(R.layout.device_list);
        //setResult(Activity.RESULT_CANCELED);
        
        Button scanButton = (Button) findViewById(R.id.button_scan);
        scanButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                doDiscovery();
                v.setVisibility(View.GONE);
            }
        });
        
        mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
        mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
        
        ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
        pairedListView.setAdapter(mPairedDevicesArrayAdapter);
        pairedListView.setOnItemClickListener(mDeviceClickListener);
        
        ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
        newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
        newDevicesListView.setOnItemClickListener(mDeviceClickListener);
        
        //注册两个过滤器,用来接收两个广播,一个是搜索到一个可用设备,一个是结束搜索
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        this.registerReceiver(mReceiver, filter);
        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        this.registerReceiver(mReceiver, filter);
        
        //获取本地蓝牙适配器,把本地已配对设备显示出来
        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) {
                mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
            }
        } else {
            String noDevices = getResources().getText(R.string.none_paired).toString();
            mPairedDevicesArrayAdapter.add(noDevices);
        }
	}
	
	//搜索
	private void doDiscovery(){
		//设置显示
		setProgressBarIndeterminateVisibility(true);
        setTitle(R.string.scanning);
        findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
        
        //如果正在搜索,取消正在搜索
        if (mBtAdapter.isDiscovering()) {
            mBtAdapter.cancelDiscovery();
        }
        
        //开始搜索
        mBtAdapter.startDiscovery();
	}
	
	//监听器
	private OnItemClickListener mDeviceClickListener = new OnItemClickListener(){

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
				long arg3) {
			// TODO Auto-generated method stub
			mBtAdapter.cancelDiscovery();
			
			//获取内容,然后把后面17位的MAC地址取出来,连接只需要MAC地址
			String info = ((TextView) arg1).getText().toString();
			String address = info.substring(info.length() - 17);
			
			//把MAC地址传回到主activity,调用setResult在finish之前传回值
			Intent intent = new Intent();
            intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
            setResult(Activity.RESULT_OK, intent);
            finish();
			
		}};
    
	//注册一个广播接收,两个不同的接收给出不同的动作
	private final BroadcastReceiver mReceiver = new BroadcastReceiver(){

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			String action = intent.getAction();
			
			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))
			{
				setProgressBarIndeterminateVisibility(false);
                setTitle(R.string.select_device);
                if (mNewDevicesArrayAdapter.getCount() == 0) 
                {
                    String noDevices = getResources().getText(R.string.none_found).toString();
                    mNewDevicesArrayAdapter.add(noDevices);
                }
			}
			
		}};

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if (mBtAdapter != null) 
		{
            mBtAdapter.cancelDiscovery();
        }
		//广播要取消注册,防止内存泄漏
		this.unregisterReceiver(mReceiver);
	}
		
	

}
BluetoothChat.java
package com.example.bluetooth;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.ActionBar;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

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;
	
	public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";
    
    private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
    private static final int REQUEST_ENABLE_BT = 3;
    
	private BluetoothAdapter mBluetoothAdapter = null;
	private BluetoothChatService mChatService = null;
	private ArrayAdapter<String> mConversationArrayAdapter;
	private ListView mConversationView;
    private EditText mOutEditText;
    private Button mSendButton;
    private StringBuffer mOutStringBuffer;
	private String mConnectedDeviceName = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		//本地如果没有蓝牙,提示没有蓝牙
		mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) 
        {
            Toast.makeText(this, "没有发现蓝牙设备", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        
        //蓝牙是否打开了,没有的话,让用户选择是否打开
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, RESULT_FIRST_USER);
        } else {
            if (mChatService == null) setupChat();
        }
        
	}

	//蓝牙是否可以被检测
	private void ensureDiscoverable() {
		// 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);
	        }
	}
	
	//信息显示
	private void setupChat() {
		// TODO Auto-generated method stub
		mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
        mConversationView = (ListView) findViewById(R.id.in);
        mConversationView.setAdapter(mConversationArrayAdapter);
        
        mOutEditText = (EditText) findViewById(R.id.edit_text_out);
        mOutEditText.setOnEditorActionListener(mWriteListener);
        
        mSendButton = (Button) findViewById(R.id.button_send);
        mSendButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                // Send a message using content of the edit text widget
                TextView view = (TextView) findViewById(R.id.edit_text_out);
                String message = view.getText().toString();
                sendMessage(message);
            }
        });
	}
	
	//EditText+Button响应,软键盘设置
	private TextView.OnEditorActionListener mWriteListener =
	        new TextView.OnEditorActionListener() {
	        public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
	            if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
	                String message = view.getText().toString();
	                sendMessage(message);
	            }
	            return true;
	        }
	    };
	
	//开始聊天服务
	@Override
	protected synchronized void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		if (mChatService != null) 
		{
            if (mChatService.getState() == BluetoothChatService.STATE_NONE) 
            {
              mChatService.start();
            }
        }
	}
  
	protected void sendMessage(String message) {
		// TODO Auto-generated method stub
		//是否已经连接,没有连接是不能发送信息的
		if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) 
		{
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
        }
		//发送信息
		if (message.length() > 0) 
		{
            byte[] send = message.getBytes();
            mChatService.write(send);
            mOutStringBuffer.setLength(0);
            mOutEditText.setText(mOutStringBuffer);
        }
		
	}

	//停止服务
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if (mChatService != null) mChatService.stop();
	}

	//设置当前连接状态的显示
	private final void setStatus(int resId) {
        final ActionBar actionBar = getActionBar();
        actionBar.setSubtitle(resId);
    }

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

    //从BluetoothChatService中读取message,更新UI显示
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
                switch (msg.arg1) {
                case BluetoothChatService.STATE_CONNECTED:
                    setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
                    mConversationArrayAdapter.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);
                mConversationArrayAdapter.add("Me:  " + writeMessage);
                break;
            case MESSAGE_READ:
                byte[] readBuf = (byte[]) msg.obj;
                // 从缓存中读信息
                String readMessage = new String(readBuf, 0, msg.arg1);
                mConversationArrayAdapter.add(mConnectedDeviceName+":  " + readMessage);
                break;
            case MESSAGE_DEVICE_NAME:
                // 保存设备名称
                mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
                Toast.makeText(getApplicationContext(), "Connected to "
                               + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_TOAST:
            	//打印toast
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
                               Toast.LENGTH_SHORT).show();
                break;
            }
        }
    };
    
    
    //DeviceActivity的结果返回响应
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
         switch (requestCode) {
         case REQUEST_CONNECT_DEVICE_SECURE:
             // 返回结果是要求一个连接
             if (resultCode == Activity.RESULT_OK) {
                 connectDevice(data, true);
             }
             break;
         case REQUEST_CONNECT_DEVICE_INSECURE:
             // 
             if (resultCode == Activity.RESULT_OK) {
                 connectDevice(data, false);
             }
             break;
         case REQUEST_ENABLE_BT:
             // 返回结果是要求打开蓝牙
             if (resultCode == Activity.RESULT_OK) {
                 setupChat();
             } else {
                 Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                 finish();
             }
         }
     }

    //连接设备
    private void connectDevice(Intent data, boolean secure) {
        String address = data.getExtras()
            .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        mChatService.connect(device, secure);
    }
    
    
    
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		Intent serverIntent = null;
        switch (item.getItemId()) {
        case R.id.secure_connect_scan:
            // Launch the DeviceListActivity to see devices and do scan
            serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
            return true;
        case R.id.insecure_connect_scan:
            // Launch the DeviceListActivity to see devices and do scan
            serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
            return true;
        case R.id.discoverable:
            // Ensure this device is discoverable by others
            ensureDiscoverable();
            return true;
        }
        return false;
		
	}
}

BluetoothChatService.java

package com.example.bluetooth;

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

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class BluetoothChatService {

	private final BluetoothAdapter mAdapter;
    private final Handler mHandler;
    private AcceptThread mSecureAcceptThread;
    private AcceptThread mInsecureAcceptThread;
    private ConnectThread mConnectThread;
    private ConnectedThread mConnectedThread;
    
    private static final String NAME_SECURE = "BluetoothChatSecure";
    private static final String NAME_INSECURE = "BluetoothChatInsecure";
    
    private static final UUID MY_UUID_SECURE =
            UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
    private static final UUID MY_UUID_INSECURE =
            UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
    	
    //设置UI的状态
	private int mState;
	public static final int STATE_NONE = 0;       // we're doing nothing
    public static final int STATE_LISTEN = 1;     // now listening for incoming connections
    public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
    public static final int STATE_CONNECTED = 3;  // now connected to a remote device
    
    public BluetoothChatService(Context context, Handler handler) {
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        //UI的动态显示,显示的是状态
        mState = STATE_NONE;
        //信息的处理线程
        mHandler = handler;
    }
    
	public int getState() {
		// TODO Auto-generated method stub
		return mState;
	}
	
	//改变UI的状态显示
	private void setState(int stateListen) {
		// TODO Auto-generated method stub
		mState = stateListen;
        mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, stateListen, -1).sendToTarget();
	}

	//建立设备之间的连接
	public void connect(BluetoothDevice device, boolean secure) {
		// TODO Auto-generated method stub
		if (mState == STATE_CONNECTING) 
		{
            if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
        }
		
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
        
        mConnectThread = new ConnectThread(device, secure);
        mConnectThread.start();
        
        setState(STATE_CONNECTING);
	}
	
	//连接失败的提示
	private void connectionFailed() {
        // 把连接失败显示在UI上
        Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothChat.TOAST, "Unable to connect device");
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        // 重新开始服务
        BluetoothChatService.this.start();
    }
	
	//连接已建立,保持连接
	public synchronized void connected(BluetoothSocket socket, BluetoothDevice
            device, final String socketType) {
        if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
        
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
        
        if (mSecureAcceptThread != null) 
        {
            mSecureAcceptThread.cancel();
            mSecureAcceptThread = null;
        }
        
        if (mInsecureAcceptThread != null) {
            mInsecureAcceptThread.cancel();
            mInsecureAcceptThread = null;
        }
        
        mConnectedThread = new ConnectedThread(socket, socketType);
        mConnectedThread.start();

        // 在UI上把当前连接的设备名显示出来
        Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
        Bundle bundle = new Bundle();
        bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
        msg.setData(bundle);
        mHandler.sendMessage(msg);

        setState(STATE_CONNECTED);
    }
	
	//连接中断
	private void connectionLost() {
        // 连接如果中断了,就在UI上提示
        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);

        // 重新开始服务
        BluetoothChatService.this.start();
    }
	
	//开始聊天服务
	public void start() {
		// TODO Auto-generated method stub
		if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
		
        if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
        
        setState(STATE_LISTEN);

        // 开始监听socket
        if (mSecureAcceptThread == null) {
            mSecureAcceptThread = new AcceptThread(true);
            mSecureAcceptThread.start();
        }
	}
	
	//停止服务
	public void stop() {
		// TODO Auto-generated method stub
		if (mConnectThread != null) 
		{
            mConnectThread.cancel();
            mConnectThread = null;
        }

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

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

        if (mInsecureAcceptThread != null) {
            mInsecureAcceptThread.cancel();
            mInsecureAcceptThread = null;
        }
        
        setState(STATE_NONE);
	}
	
	
	//监听连接请求线程
	private class AcceptThread extends Thread{
		//本地socket
		 private final BluetoothServerSocket mmServerSocket;
		 private String mSocketType;
		 
	     public AcceptThread(boolean secure){
	    	 BluetoothServerSocket tmp = null;
	    	 mSocketType = secure ? "Secure":"Insecure";

            // 创建一个新的服务socket
            try {
                if (secure) {
                    tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
                        MY_UUID_SECURE);
                } else {
                    tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
                            NAME_INSECURE, MY_UUID_INSECURE);
                }
            } catch (IOException e) {
            }
            mmServerSocket = tmp;
	     }
	     
	     public void run() {
	            setName("AcceptThread" + mSocketType);
	            BluetoothSocket socket = null;

	            //没有建立连接
	            while (mState != STATE_CONNECTED) {
	                try {
	                    socket = mmServerSocket.accept();
	                } catch (IOException e) {
	                    break;
	                }

                // 建立了连接
                if (socket != null) {
                    synchronized (BluetoothChatService.this) {
                        switch (mState) {
                        case STATE_LISTEN:
                        case STATE_CONNECTING:
                            connected(socket, socket.getRemoteDevice(),
                                    mSocketType);
                            break;
                        case STATE_NONE:
                        case STATE_CONNECTED:
                            try {
                                socket.close();
                            } catch (IOException e) {
                            }
                            break;
                        }
                    }
                }
	        }
	     }
	     
	     public void cancel() {
	            try {
	                mmServerSocket.close();
	            } catch (IOException e) {
	            }
	        }
	     
	}
	
	//连接线程
	private class ConnectThread extends Thread {
        private final BluetoothSocket mmSocket;
        private final BluetoothDevice mmDevice;
        private String mSocketType;

        public ConnectThread(BluetoothDevice device, boolean secure) {
            mmDevice = device;
            BluetoothSocket tmp = null;
            mSocketType = secure ? "Secure" : "Insecure";

            //连接
            try {
                if (secure) {
                    tmp = device.createRfcommSocketToServiceRecord(
                            MY_UUID_SECURE);
                } else {
                    tmp = device.createInsecureRfcommSocketToServiceRecord(
                            MY_UUID_INSECURE);
                }
            } catch (IOException e) {
            }
            mmSocket = tmp;
        }

        public void run() {
            setName("ConnectThread" + mSocketType);

            mAdapter.cancelDiscovery();
            //连接到BluetoothSocket
            try {
                mmSocket.connect();
            } catch (IOException e) {
                try {
                    mmSocket.close();
                } catch (IOException e2) {
                }
                connectionFailed();
                return;
            }

            // 取消连接线程
            synchronized (BluetoothChatService.this) {
                mConnectThread = null;
            }

            // 开始连接线程
            connected(mmSocket, mmDevice, mSocketType);
        }

        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
            }
        }
    }
	
	
    
	//已连接线程,通过这个线程发送和接收数据
	private class ConnectedThread extends Thread {
		private final BluetoothSocket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        
        //初始化
        public ConnectedThread(BluetoothSocket socket, String socketType){
        	mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            
            try {
            	//得到输入输出数据流
				tmpIn = socket.getInputStream();
				tmpOut = socket.getOutputStream();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            
            mmInStream = tmpIn;
            mmOutStream = tmpOut; 
        }
        
       //读
       public void run(){
    	   byte[] buffer = new byte[1024];
           int bytes;
           //长连接
           while (true) {
               try {
                   bytes = mmInStream.read(buffer);
                   // 把信息反馈给UI界面显示出来
                   mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
                           .sendToTarget();
               } catch (IOException e) {
                   connectionLost();
                   // 重新开始服务
                   BluetoothChatService.this.start();
                   break;
               }
           }
       } 
       
       //写
       public void write(byte[] buffer) {
           try {
               mmOutStream.write(buffer);
               mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
                       .sendToTarget();
           } catch (IOException e) {
           }
       }
       
       public void cancel() {
           try {
               mmSocket.close();
           } catch (IOException e) {
           }
       }
        
	}
	
	//写接口
		public void write(byte[] send) {
			// TODO Auto-generated method stub
			ConnectedThread r;
	        synchronized (this) {
	            if (mState != STATE_CONNECTED) return;
	            r = mConnectedThread;
	        }
	        r.write(send);
		}
	
		
}



      


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章