Android----蓝牙通信使用 不同手机下同一应用通信

  

</pre><p>---------有人说学到东西不是在做的过程,而是在总结整理的时候!</p><p>          自己没有多少开发Android的经验,对于很多问题都是不太清楚,最近有个想法需要实现两部手机的相互通信,互相动态改变对方手机上的内容,达到两部手机显示同样内容的目的。最开始想到的是网络通信,但是需要用到服务器,或者说这样受限很多,速度上也可能会降低。最后定位到蓝牙这个功能。然后就是找资料看书。。。</p><p>          为了证明自己的想法能够实现,所以决定先实现一个简单的蓝牙连接,并且能互传一段文字的功能。然后经过一天的努力终于实现了~~~虽然很简单,为了理清自己接下来的问题,先写篇博文总结下蓝牙的连接和通信,也好提炼出一个后面可以利用的东西。</p><p>     自己看的资料大都将的非常全面,但是对于自己一步步尝试还是有些模糊。</p><p>一、 首先介绍的是BlueToothAdapter  借助于这个东西你可以初始化蓝牙设备,与蓝牙设备进行连接,创建Socket等等非常重要。</p><p><pre name="code" class="java">BluetoothAdapter bluetooth=BluetoothAdapter.getDefaultAdapter();


我们会去使用上面的方法来获取本地设备,之后就可以这个设备进行想做的事情。

   待会会说怎么去用,接下来我们来想象一下一台手机蓝牙的工作流程,也就是在我们自己的app里应该实现的东西


大概分为以上几个部分,大家要明白的是,我们进行蓝牙连接,应该是实现两部手机相同app的通信(也就是我们自己的app了),当然也有很多与其他提供蓝牙服务的app通信的情况,不过我觉得实现单一app通信足够理解蓝牙通信过程。

1.打开蓝牙:

   下面是一段打开蓝牙的code,bluetooth就是本地蓝牙设备(可以这么理解)

 private void initBluetooth()
    {//判断设备是否开启蓝牙,若没开启则打开开启蓝牙界面供用户选择
    	if(!this.bluetooth.isEnabled())//这个bluetooth就是利用BluetoothAdapter.getDefaultAdapter()获取到的BluetoothAdapter对象
    	{
    	Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    	startActivityForResult(intent, ENABLE_BLUETOOTH);

    	}
    	else
    	{
    		Toast.makeText(MainActivity.this, "BlueTooth open Already", 2000).show();
    		
    	}
    }

  如果用户在执行上面代码之前没有打开蓝牙,那么用户手机将会显示这么一个界面,让用户选择是否打开蓝牙,根据用户不同的选择页面将会返回不同的值


根据StartActivityForResult返回值的不同进行相应操作。如果不OK得话,你可以一直请求用户开蓝牙~~~~~,那么就这样简单的完成了step one

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	// TODO Auto-generated method stub
	if(requestCode==ENABLE_BLUETOOTH)
	{
        if(requestCode==RESULT_OK)
        {
        	Toast.makeText(MainActivity.this, "BlueTooth open", 2000).show();
        	
        }
        else
        {
        	Toast.makeText(MainActivity.this, "oooops not lucky", 2000).show();
        }
	}
	else if(requestCode==DISCOVERABLE_BLUETOOTH)
	{
		if(resultCode==RESULT_CANCELED)
		{
			Toast.makeText(MainActivity.this, "just ok man !", 2000).show();
		}
	}
}


2.设置模式

   可能并无模式这种说法,实际上就是设置一下自己可不可以被人发现什么的,分为下面三种

  SCAN_MODE_CONNECTABLE_DISCOVERABLE 启用查询扫描和页面扫描,意味着设备可以被任意执行发现扫描的蓝牙设备发现

  SCAN_MODE_CONNECTABLE 启用页面扫描禁用查询扫描,意味着只有先前连接过的设备可以查询到本设备

  SCAN_MODE_NONE 当然就是不可发现喽!

设置模式的代码也很简单:

private void disCoverable()
    {
    	startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE), DISCOVERABLE_BLUETOOTH);
    }
和请求打开蓝牙类似,也是会调起一个Preference Activity,用户进行选择,之后返回一个值,根据返回值去做什么这就是我们自己的事了。

注意 一般默认可被发现时间为两分钟也就是120秒,当然这个值可以在启动的Intent中进行设置。

用户手机将会显示上面界面

问题来了,程序刚刚运行就弹出两个选择框,这样的用户体验真实差的不可容忍,听说也有默认设置的办法(不给用户选择的权利),这个今后学到了再说!


3.搜索周边设备

   先上代码君~~~~

 if(this.bluetooth.isEnabled())
        {
        	this.bluetooth.startDiscovery();
        }


没错就这么一行,关键代码,手机就开始自动搜索了,八国只用这一行是肯定记录不下来搜索出的设备信息,而且也不知道设备是何时搜索完成!那么Android中的一方霸主BroadCaster出场了,注册广播接收器,来获取搜索状态!

接下来是接收器的代码

下面这个接收开始和结束的广播,(结束后大家可以把获取的的设备信息进行展示,或者把搜索动画停掉=====)

public class discoverMonitor extends BroadcastReceiver{
	private String discoverStarted=BluetoothAdapter.ACTION_DISCOVERY_STARTED;
	private String discoverFinished=BluetoothAdapter.ACTION_DISCOVERY_FINISHED;
	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
	  if(discoverStarted.equals(intent.getAction()))//搜索开始
	  {
//		  Toast.makeText(context, "here we go-----discover started", 2000).show();
		  Log.i("---------->", "here we go-----discover started");
	  }
	  else if(discoverFinished.equals(intent.getAction()))//搜索结束
	  {
//		  Toast.makeText(context, "we have finished-----discover finished", 2000).show();
		  Log.i("---------->", "we have finished-----discover finished");
	  }
		
	}

}

接下来是搜索到设备的广播接收者,手机每搜到一个就会发出一个广播,所以得到搜索到的设备的信息这里是关键

public class discoverResult extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		String remoteDeviceName=intent.getStringExtra(BluetoothDevice.EXTRA_NAME);//设备名称
		BluetoothDevice remoteDevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);//获取搜索到的设备信息
		bluetoothDevice device=new bluetoothDevice();//自己写的类
		if(remoteDeviceName!=null)
		{
			device.setremoteDeviceName(remoteDeviceName);
		}
		if(remoteDevice!=null)
		{
			device.setremoteDevice(remoteDevice);
		}
		DeviceCollect.Devices.add(device);//加到一个ArrayList中
		Toast.makeText(context, "en....one more", 2000).show();
		Log.i("---------->", "en ------one more devices");
	}

}

当然不能忘了进行注册,注意要在执行搜索代码前进行注册

  private void registerBR()
    {
    	registerReceiver(new discoverMonitor(), new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED));
    	registerReceiver(new discoverMonitor(), new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
    	registerReceiver(new discoverResult(), new IntentFilter(BluetoothDevice.ACTION_FOUND));
    }

bluetoothDevice类

public class bluetoothDevice {
	private String remoteDeviceName;
	private BluetoothDevice remoteDevice;
	public String getremoteDeviceName()
	{
		return this.remoteDeviceName;
	}
	public BluetoothDevice getremBluetoothDevice()
	{
		return this.remoteDevice;
	}
	public void setremoteDeviceName(String name)
	{
		this.remoteDeviceName=name;
	}
	public void setremoteDevice(BluetoothDevice device)
	{
		this.remoteDevice=device;
	}

}

DeviceCollect类

public class DeviceCollect {

	public static ArrayList<bluetoothDevice> Devices;
	static
	{
		DeviceCollect.Devices=new ArrayList<bluetoothDevice>();
	}
}
3.列出所有设备,选择其中进行连接

    这个部分其实是关键,还是像一开始说的我们要实现两部手机同一app的通信,这就意味着我们的app要能接收连接请求,并且还能发出连接请求!想明白这些其实也就简单了,就是说和网络通信类似,我们app里既要运行着server代码,还要能主动发出client请求!

   我没有把列出设备作为重点,所以我没列出设备,但是通过第二步已经拿到了周边设备信息放在了ArrayList里,想要列出的话用ListView就可以了,然后通过单击不同的Item进行连接。

那么。我们就假设已经获取到了一个Item中的设备信息我想去连接这个设备。此时我就是要做Client了,要求对方必须等待着client的请求(运行着server代码)

我们先来看看Server代码

private UUID startServerSocket(BluetoothAdapter bluetooth)
{
	UUID uuid=UUID.fromString("a60f35f0-b93a-11de-8a39-08002009c666");//设置一个UUID
	String name="bluetoothserver";
	try{
		final BluetoothServerSocket btserver=bluetooth.listenUsingRfcommWithServiceRecord(name, uuid);//监听连接请求
		Thread acceptTread=new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				BluetoothSocket serverSocket;
				try {Log.i("------------>", "waitforconnect  now be Server");
					serverSocket = btserver.accept();//连接建立前保持阻塞
					Log.i("connectToServerSocket------------>", "OK connected");
					Message what=handler.obtainMessage();
					what.arg1=0x31;
					handler.sendMessage(what);//只是为了toast
					transferSocket=serverSocket;//为了能进行发送信息
					while(true)//一直监听传入的数据
					{
					listenForMessages(serverSocket, new StringBuilder());//监听传入数据的函数
					}
				
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}); 
		acceptTread.start();
	}
	catch(IOException e)
	{
		e.printStackTrace();
	}
	
	return uuid;
}

上面有个UUID(全局统一标示),这就是我们自己的APP能够在不同手机上通过蓝牙进行连接的关键,首先我的程序作为server在等待着一个请求时UUID为上面code中数据的Client请求。其他app默认情况下不可能知道我程序内设置的UUID,这也就保证了只有自己的APP可以发出这样的请求。

bluetooth.listenUsingRfcommWithServiceRecord(name, uuid);  调用这个方法就可以实现监听一个传入的连接请求


Client请求代码


public void connectToServerSocket(BluetoothDevice device,UUID uuid)
{ 
	try{
		final BluetoothSocket clientSocket=device.createRfcommSocketToServiceRecord(uuid);//创建客户端socket
		Thread connectthread=new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					Log.i("------------>", "waitforconnect  now be client");
					clientSocket.connect();
					Log.i("connectToServerSocket------------>", "OK connected");
					Message what=handler.obtainMessage();
					what.arg1=0x31;
					handler.sendMessage(what);
					transferSocket=clientSocket;//套接字
					while(true)
					{
					listenForMessages(clientSocket, new StringBuilder());
					}
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}); 
		connectthread.start();
	}catch(IOException e)
	{
		e.printStackTrace();
	}
}

device.createRfcommSocketToServiceRecord(uuid);//创建客户端Socket  

要保证UUID正确性,也就是和server端等待的是相同的。

根据返回的套接字就可以进行通信了,这个网络通信差不太多。

5.数据传递

这个就不说了。。。我自己写的程序里有这一部分。可以看下。首先我要说,程序写的很烂,可复用的部分也不是很多,因为我刚刚理清思路,还不知道如何去安排代码。也希望对这个比较熟悉的朋友能够给出推荐,给个好的Demo最好了。


关键的别忘了在Manifest里声明权限

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


第一次发文,语言组织力简直弱爆~~,也希望以后能有所进步,比较乱,大家见谅


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【RT-Thread 作品秀】基于RT-Thread的网络照相机作者:吴顶顶 概述随着科技的进步和互联网的发展,基于物联网的可拍照设备也越来越多的融入到人们的生活中来,例如在超市中,管理者利用拍照设备定时抓取货架照片,分析货物状态,并补充、优化货物摆放;在酒吧里,管理者会利用拍照设备定时抓拍酒架照片,传送到网络平台供大众浏览,以招揽更多顾客。本网络照相机基于STM32H7+RTThread平台,采集摄像头数据,并通过无线网络传送到服务器,提供SD卡配网、手动拍摄、定时拍摄、照片推送等功能,并提供windows上位机提供控制和照片显示功能。 主要功能有: 格式化sd卡:格式化sd卡,但是会保留网络配置文件,其他文件全部删除 设备重启:重启设备 实时拍照:发送指令给照相机,照相机拍照,并把照片回传 定时拍照:照相机依据下发的拍照时间,在时间到达时拍摄一张照片,并传给服务器 按键拍照:点击板上用户按钮,拍摄一张照片,并传给服务器 定时任务:可以新建/删除/查询定时拍照任务,任务存储在sd卡中,重启有效 开发环境硬件:ART-PI(STM32H750主控)+ OV2640模组 RT-Thread版本:4.0.3 SDK 版本:1.0.1 开发工具及版本:RT-Thread Studio 1.1.5, Qt5.14.0 RT-Thread使用情况概述内核部分:调度器,信号量,互斥锁,内存管理 调度器:多任务调度 信号量:用于唤醒对应任务 互斥锁:用于互斥资源独占访问 内存管理:动态内存申请与释放 组件部分:虚拟文件系统,IPC,I2C,RTC,NTP 虚拟文件系统:文件操作,sd卡、照片文件 IPC:mqtt发送数据需要 I2C:配置摄像头模块需要 RTC和NTP:同步时间 软件包部分:paho mqtt,cJSON,netutils pahomqtt:用于和服务器通信 cJSON:解析、封装mqtt消息 netutils:NTP网络对时 其他:base64 用于将图片文件转换成字符串,便于mqtt传输 硬件框架总体的硬件框架如下图所示: 本网络摄像机硬件结果较为简单,即art-pi连接一个摄像头模组,art-pi板上用到了AP6212无线模块,外部内存,led指示灯,和sd卡。其中,摄像头模块用于采集图像信号;AP6212用于和服务器进行通信;因一张图像数据量较大,片内内存不够,故而使用外部内存;led灯用于指示设备工作状态;sd卡用于保存网络、服务器、和定时任务配置。 软件框架说明整体的软件框架如下图所示,网络照相机内部有一个proxy线程,负责和云端进行通信,在接收到云端消息后会解析,并分发到其他的线程执行,然后将执行结果返回到云端;照相机发生了其他的事件,例如用户按键拍照,也会将数据传给proxy线程,proxy线程再将数据发送到云端。用户通过上位机终端软件连接上云服务器,实现与照相机的通信控制。 整个系统支持接入多个照相机,如下图所示,不同的照相机通过sd卡配置文件中sn进行区分,上位机软件可以显示所有在线的照相机,但同一时间只支持操作一个。 软件模块说明1. 用户线程创建流程如下图所示为用户线程创建流程 用户线程作用描述如下: main:用于创建sd_card 线程,检测按键事件,闪灯; sd_card:用于管理与sd卡相关的工作,包括拍照,网络配置,定时任务; network:负责联网,根据sd卡的配置文件连接到指定的wifi网络; proxy:负责启动mqtt,并管理与云端的通信,其他线程都需要通过proxy线程与云端交互数据; event:定时任务和按键任务,在定时时间到达时,或者用户按键时拍摄照片并通过proxy上传云端。 2. 通信接口及流程2.1 MQTT订阅主题设备向服务器订阅主题: /ter/query/discovery,用于接收设备发现消息 /ter/sn/request,用于接收针对该设备的指令,其中sn为设备的SN号,下同 客户端向服务器订阅主题: /dev/response/discovery,用于接收设备发现回复 /dev/response/will,用于接收设备遗嘱消息 /dev/sn/response,用于接收设备操作指令回复 /dev/sn/event,用于接收设备的通知 2.2 设备发现所有的设备均订阅/ter/query/discovery主题,客户端向该主题发布发现消息,所有收到消息的设备向/dev/response/discovery回复一条消息,而客户端又订阅了/dev/response/discovery主题,故而便可以知道哪些设备在线了。 设备连上服务器的时候,会定义一个遗嘱消息,主题为/dev/sn/will,客户端订阅了该主题,当设备因为某些原因掉线,则超过一定时间之后,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值