Android Studio 的蓝牙串口通信(附Demo源码下载)
根据相关代码制作了一个开源依赖包,将以下所有的代码进行打包,直接调用即可完成所有的操作。详细说明地址如下,如果觉得有用可以GIthub点个Star支持一下:
Android Studio 的蓝牙串口通信
这次做项目用到了蓝牙串口,折腾了两天总算弄出来了,记录一下方便以后回顾。
获取相关权限
获取蓝牙权限
在 AndroidManifest.xml文件中加入如下代码,(其实这俩句可以先不加,在工程中写到相应语句的时候可以Alt+Enter添加)
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
再加上定位权限,这是Android 6.0 以上一定需要注意的地方,同时最好在代码里加上判断是否获取定位权限的代码(就是这个该死的玩意儿耽误我好长时间)
AndroidManifest.xml中
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
判断是否获取定位权限(这里我是写在了扫描未配对蓝牙设备的地方,当然也可以直接放在程序刚开始)
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){//未开启定位权限
//开启定位权限,200是标识码
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},200);
}else{
// 显示其它设备(未配对设备)列表
findViewById(R.id.textView).setVisibility(View.VISIBLE);
// 关闭再进行的服务查找
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
}
}
上述判断发现未开启之后会自动回调函数区开启,这里手动实现代码如下
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 200:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
doDiscovery();
}else{
finish();
}
break;
default:
}
}
权限方面的事情完了(我并不是在程序刚开始的地方考虑的,这一点很不好,后续版本会改掉 ,这里就懒得弄了,嘿嘿)
接下来判断蓝牙是否打开
//如果打不开蓝牙提示信息,结束程序
if (mBluetoothAdapter == null){
Toast.makeText(getApplicationContext(),"无法打开手机蓝牙,请确认手机是否有蓝牙功能!",Toast.LENGTH_SHORT).show();
finish();
return;
}
连接按钮的响应
final Button connectButton = findViewById(R.id.connectButton);
connectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBluetoothAdapter.isEnabled() == false) {
Toast.makeText(getApplicationContext(), " 请先打开蓝牙", Toast.LENGTH_LONG).show();
return;
}
//如果未连接设备则打开DevicesListActivity搜索设备
if (mBluetoothSocket == null) {
Intent serveIntent = new Intent(getApplicationContext(), DevicesListActivity.class); //跳转活动
startActivityForResult(serveIntent, 1); //设置返回宏定义
} else {
//关闭连接socket
try {
bRun = false;
Thread.sleep(2000);
is.close();
mBluetoothSocket.close();
mBluetoothSocket = null;
connectButton.setText("连接");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
发送按钮响应
Button sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int n = 0;
if (mBluetoothSocket == null) {
Toast.makeText(getApplicationContext(), "请先连接设备", Toast.LENGTH_SHORT).show();
return;
}
if (sendEditText.getText().length() == 0) {
Toast.makeText(getApplicationContext(), "请先输入数据", Toast.LENGTH_SHORT).show();
return;
}
try {
OutputStream os = mBluetoothSocket.getOutputStream(); //蓝牙连接输出流
byte[] bos = sendEditText.getText().toString().getBytes();
for (int i = 0; i < bos.length; i++) {
if (bos[i] == 0x0a) n++;
}
byte[] bos_new = new byte[bos.length + n];
n = 0;
for (int i = 0; i < bos.length; i++) { //手机中换行为0a,将其改为0d 0a后再发送
if (bos[i] == 0x0a) {
bos_new[n] = 0x0d;
n++;
bos_new[n] = 0x0a;
} else {
bos_new[n] = bos[i];
}
n++;
}
os.write(bos_new);
} catch (IOException e) {
e.printStackTrace();
}
}
});
设备可以被搜索设置(这里就看个人需求了,我是没用上这个)
new Thread(){
public void run(){
if(mBluetoothAdapter.isEnabled()==false){
mBluetoothAdapter.enable();
}
}
}.start();
接收活动结果,主要是扫面活动传来的连接信息
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1: //连接结果,由DeviceListActivity设置返回
// 响应返回结果
if (resultCode == Activity.RESULT_OK) { //连接成功,由DeviceListActivity设置返回
// MAC地址,由DeviceListActivity设置返回
String address = data.getExtras().getString(DevicesListActivity.EXTRA_DEVICE_ADDRESS);
// 得到蓝牙设备句柄
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
// 用服务号得到socket
try {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));
} catch (IOException e) {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
}
//连接socket
Button connectButton = findViewById(R.id.connectButton);
try {
mBluetoothSocket.connect();
Toast.makeText(this, "连接" + mBluetoothDevice.getName() + "成功!", Toast.LENGTH_SHORT).show();
connectButton.setText("断开");
} catch (IOException e) {
try {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
mBluetoothSocket.close();
mBluetoothSocket = null;
} catch (IOException ee) {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
}
return;
}
//打开接收线程
try {
is = mBluetoothSocket.getInputStream(); //得到蓝牙数据输入流
} catch (IOException e) {
Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();
return;
}
if (bThread == false) {
readThread.start();
bThread = true;
} else {
bRun = true;
}
}
break;
default:
break;
}
}
接收线程
//接收数据线程
Thread readThread=new Thread(){
public void run(){
int num = 0;
byte[] buffer = new byte[1024];
byte[] buffer_new = new byte[1024];
int i = 0;
int n = 0;
bRun = true;
//接收线程
while(true){
try{
while(is.available()==0){
while(bRun == false){}
}
while(true){
if(!bThread)//跳出循环
return;
num = is.read(buffer); //读入数据
n=0;
String s0 = new String(buffer,0,num);
for(i=0;i<num;i++){
if((buffer[i] == 0x0d)&&(buffer[i+1]==0x0a)){
buffer_new[n] = 0x0a;
i++;
}else{
buffer_new[n] = buffer[i];
}
n++;
}
String s = new String(buffer_new,0,n);
smsg+=s; //写入接收缓存
if(is.available()==0)break; //短时间没有数据才跳出进行显示
}
//发送显示消息,进行显示刷新
handler.sendMessage(handler.obtainMessage());
}catch(IOException e){
}
}
}
};
消息显示的处理队列
Handler handler= new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
tv_in.setText(smsg); //显示数据
scrollView.scrollTo(0,tv_in.getMeasuredHeight()); //跳至数据最后一页
}
};
至此,接收发送部分已经全部结束,然后就是扫描设备部分了
这部分我直接贴出整个活动的代码了 注释比较齐全 就不哔哔了
package com.example.btcontroller;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
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.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Set;
public class DevicesListActivity extends AppCompatActivity {
private static final String TAG = "DevicesListActivity";
public static String EXTRA_DEVICE_ADDRESS = "设备地址";
//成员域
private BluetoothAdapter mBluetoothAdapter; //蓝牙适配器
private ArrayAdapter<String> mPairedDevicesArrayAdapter; //已配对的设备适配器
private ArrayAdapter<String> mUnPairedDevicesArrayAdapter; //未配对的设备适配器
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_devices_list);
//设定默认返回值为取消
setResult(Activity.RESULT_CANCELED);
// 初使化设备适配器存储数组
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mUnPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
// 设置已配队设备列表
ListView pairedListView = (ListView) findViewById(R.id.pairedListView);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener( mDeviceClickListener);
// 设置新查找设备列表
ListView newDevicesListView = (ListView) findViewById(R.id.unPairedListView);
newDevicesListView.setAdapter(mUnPairedDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
// 注册接收查找到设备action接收器
this.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
// 注册查找结束action接收器
//filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
this.registerReceiver(mReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED));
// 得到本地蓝牙句柄
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 得到已配对蓝牙设备列表
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
//添加已配对设备到列表并显示
if (pairedDevices.size() > 0) {
findViewById(R.id.pairedListView).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = "没有找到已配对的设备。" ;
mPairedDevicesArrayAdapter.add(noDevices);
}
//取消按键的响应函数
Button cancelButton = (Button) findViewById(R.id.cancelButton);
cancelButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭服务查找
if (mBluetoothAdapter != null) {
mBluetoothAdapter.cancelDiscovery();
}
// 注销action接收器
this.unregisterReceiver(mReceiver);
}
/**
* 开始服务和设备查找
*/
private void doDiscovery() {
// if (D) Log.d(TAG, "doDiscovery()");
// 在窗口显示查找中信息
setTitle("查找设备中...");
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){//未开启定位权限
//开启定位权限,200是标识码
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_FINE_LOCATION},200);
}else{
// 显示其它设备(未配对设备)列表
findViewById(R.id.textView).setVisibility(View.VISIBLE);
// 关闭再进行的服务查找
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
}
}
//加载菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
//菜单项的响应
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.scanItem:
doDiscovery();
break;
default:
}
return true;
}
// 选择设备响应函数
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
// 准备连接设备,关闭服务查找
mBluetoothAdapter.cancelDiscovery();
// 得到mac地址
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// 设置返回数据
Intent intent = new Intent();
intent.putExtra("设备地址", address);
// 设置返回值并结束程序
setResult(Activity.RESULT_OK, intent);
finish();
}
};
// 查找到设备和搜索完成action监听器
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 查找到设备action
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// 得到蓝牙设备
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 如果是已配对的则略过,已得到显示,其余的在添加到列表中进行显示
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
mUnPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}else{ //添加到已配对设备列表
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
// 搜索完成action
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
setTitle("选择要连接的设备");
if (mUnPairedDevicesArrayAdapter.getCount() == 0) {
String noDevices = "没有找到新设备";
mUnPairedDevicesArrayAdapter.add(noDevices);
}
}
}
};
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 200:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
doDiscovery();
}else{
finish();
}
break;
default:
}
}
}
主活动的代码
package com.example.btcontroller;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private final static String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB"; //SPP服务UUID号
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //获取蓝牙实例
private EditText sendEditText; //创建发送 句柄
private TextView tv_in; //接收显示句柄
private ScrollView scrollView; //翻页句柄
private String smsg = ""; //显示用数据缓存
BluetoothDevice mBluetoothDevice = null; //蓝牙设备
BluetoothSocket mBluetoothSocket = null; //蓝牙通信Socket
boolean bRun = true; //运行状态
boolean bThread = false; //读取线程状态
private InputStream is; //输入流,用来接收蓝牙数据
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件ID
sendEditText = findViewById(R.id.sendEditText);
scrollView = findViewById(R.id.receiveScrolView);
tv_in = findViewById(R.id.in);
//如果打不开蓝牙提示信息,结束程序
if (mBluetoothAdapter == null){
Toast.makeText(getApplicationContext(),"无法打开手机蓝牙,请确认手机是否有蓝牙功能!",Toast.LENGTH_SHORT).show();
finish();
return;
}
//连接按钮响应
final Button connectButton = findViewById(R.id.connectButton);
connectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBluetoothAdapter.isEnabled() == false) {
Toast.makeText(getApplicationContext(), " 请先打开蓝牙", Toast.LENGTH_LONG).show();
return;
}
//如果未连接设备则打开DevicesListActivity搜索设备
if (mBluetoothSocket == null) {
Intent serveIntent = new Intent(getApplicationContext(), DevicesListActivity.class); //跳转活动
startActivityForResult(serveIntent, 1); //设置返回宏定义
} else {
//关闭连接socket
try {
bRun = false;
Thread.sleep(2000);
is.close();
mBluetoothSocket.close();
mBluetoothSocket = null;
connectButton.setText("连接");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
//发送按钮响应
Button sendButton = (Button) findViewById(R.id.sendButton);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int n = 0;
if (mBluetoothSocket == null) {
Toast.makeText(getApplicationContext(), "请先连接设备", Toast.LENGTH_SHORT).show();
return;
}
if (sendEditText.getText().length() == 0) {
Toast.makeText(getApplicationContext(), "请先输入数据", Toast.LENGTH_SHORT).show();
return;
}
try {
OutputStream os = mBluetoothSocket.getOutputStream(); //蓝牙连接输出流
byte[] bos = sendEditText.getText().toString().getBytes();
for (int i = 0; i < bos.length; i++) {
if (bos[i] == 0x0a) n++;
}
byte[] bos_new = new byte[bos.length + n];
n = 0;
for (int i = 0; i < bos.length; i++) { //手机中换行为0a,将其改为0d 0a后再发送
if (bos[i] == 0x0a) {
bos_new[n] = 0x0d;
n++;
bos_new[n] = 0x0a;
} else {
bos_new[n] = bos[i];
}
n++;
}
os.write(bos_new);
} catch (IOException e) {
e.printStackTrace();
}
}
});
// 设置设备可以被搜索
new Thread(){
public void run(){
if(mBluetoothAdapter.isEnabled()==false){
mBluetoothAdapter.enable();
}
}
}.start();
}
//接收活动结果,响应startActivityForResult()
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1: //连接结果,由DeviceListActivity设置返回
// 响应返回结果
if (resultCode == Activity.RESULT_OK) { //连接成功,由DeviceListActivity设置返回
// MAC地址,由DeviceListActivity设置返回
String address = data.getExtras().getString(DevicesListActivity.EXTRA_DEVICE_ADDRESS);
// 得到蓝牙设备句柄
mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(address);
// 用服务号得到socket
try {
mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));
} catch (IOException e) {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
}
//连接socket
Button connectButton = findViewById(R.id.connectButton);
try {
mBluetoothSocket.connect();
Toast.makeText(this, "连接" + mBluetoothDevice.getName() + "成功!", Toast.LENGTH_SHORT).show();
connectButton.setText("断开");
} catch (IOException e) {
try {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
mBluetoothSocket.close();
mBluetoothSocket = null;
} catch (IOException ee) {
Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();
}
return;
}
//打开接收线程
try {
is = mBluetoothSocket.getInputStream(); //得到蓝牙数据输入流
} catch (IOException e) {
Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();
return;
}
if (bThread == false) {
readThread.start();
bThread = true;
} else {
bRun = true;
}
}
break;
default:
break;
}
}
//接收数据线程
Thread readThread=new Thread(){
public void run(){
int num = 0;
byte[] buffer = new byte[1024];
byte[] buffer_new = new byte[1024];
int i = 0;
int n = 0;
bRun = true;
//接收线程
while(true){
try{
while(is.available()==0){
while(bRun == false){}
}
while(true){
if(!bThread)//跳出循环
return;
num = is.read(buffer); //读入数据
n=0;
String s0 = new String(buffer,0,num);
for(i=0;i<num;i++){
if((buffer[i] == 0x0d)&&(buffer[i+1]==0x0a)){
buffer_new[n] = 0x0a;
i++;
}else{
buffer_new[n] = buffer[i];
}
n++;
}
String s = new String(buffer_new,0,n);
smsg+=s; //写入接收缓存
if(is.available()==0)break; //短时间没有数据才跳出进行显示
}
//发送显示消息,进行显示刷新
handler.sendMessage(handler.obtainMessage());
}catch(IOException e){
}
}
}
};
//消息处理队列
Handler handler= new Handler(){
public void handleMessage(Message msg){
super.handleMessage(msg);
tv_in.setText(smsg); //显示数据
scrollView.scrollTo(0,tv_in.getMeasuredHeight()); //跳至数据最后一页
}
};
//关闭程序掉用处理部分
public void onDestroy(){
super.onDestroy();
if(mBluetoothSocket!=null) //关闭连接socket
try{
mBluetoothSocket.close();
}catch(IOException e){}
// _bluetooth.disable(); //关闭蓝牙服务
}
}
Demo源码下载 https://download.csdn.net/download/qq_41121080/11954958
Android Studio 的蓝牙串口通信(附Demo源码下载)的更多相关文章
- Asp.net MVC集成Google Calendar API(附Demo源码)
Asp.net MVC集成Google Calendar API(附Demo源码) Google Calendar是非常方便的日程管理应用,很多人都非常熟悉.Google的应用在国内不稳定,但是在国外 ...
- winserver的consul部署实践与.net core客户端使用(附demo源码)
winserver的consul部署实践与.net core客户端使用(附demo源码) 前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...
- 近期热门微信小程序demo源码下载汇总
近期微信小程序demo源码下载汇总,乃小程序学习分析必备素材!点击标题即可下载: 即速应用首发!原创!电商商场Demo 优质微信小程序推荐 -秀人美女图 图片下载.滑动翻页 微信小程序 - 新词 GE ...
- 物流一站式单号查询之快递鸟API接口(附Demo源码)
连载篇提前看 物流一站式单号查询之快递鸟API接口 物流一站式查询之TrackingMore篇 物流一站式查询之顺丰接口篇 物流一站式查询之快递100 前情提要 前三篇中,我们已经从注册.申请接口.调 ...
- 基于spring-boot和docker-java实现对docker容器的动态管理和监控[附完整源码下载]
(我是个封面) docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,doc ...
- Android 二维码 生成和识别(附Demo源码)
今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技 ...
- 【转】Android 二维码 生成和识别(附Demo源码)--不错
原文网址:http://www.cnblogs.com/mythou/p/3280023.html 今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. ...
- .NET gRPC 核心功能初体验,附Demo源码
gRPC是高性能的RPC框架, 有效地用于服务通信(不管是数据中心内部还是跨数据中心). 由Google开源,目前是一个Cloud Native Computing Foundation(CNCF)孵 ...
- 网络语音视频技术浅议(附多个demo源码下载)
我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...
随机推荐
- [XNUCA 进阶篇](web)writeup
XNUCA 靶场练习题writeup default 阳关总在风雨后 题目过滤很多,*,#,/ ,and,or,|,union,空格,都不能用 盲注,最后的姿势是:1'%(1)%'1 中间的括号的位置 ...
- 查找goog13的ip
C:\Users\Deen>ping 172.217.24.14 Pinging 172.217.24.14 with 32 bytes of data: Reply from 172.217. ...
- 题解0004:单词接龙(洛谷P1019)
题目描述:已知一组单词,给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中出现两次),在两个单词相连时,其重合部分合为一部分. 题 ...
- 在线Remix链接本地文件夹
问题 1.本地Remix环境版本滞后于在线编译器,新版本的语法在旧版本编译器中出现错误. 2.没有配置Vscode编译器,不便导入项目. 解决方案 *本解决方案基于Mac系统 创建共享文件夹 在本地创 ...
- CF1553X Harbour.Space Scholarship Contest 2021-2022 (Div. 1 + Div. 2)
掉大分 E 对于一个序列,把它排回去的最小次数是 $\sum置换环大小-1=错位个数-置换环个数$ 注意到m小于等于n/3.那么最多修正2m个错位.正确位置的个数必须大于等于n/3才可能在m次内修正. ...
- Eclipse建立Web项目,手动生成web.xml文件
相关文章:https://blog.csdn.net/ys_code/article/details/79156188(Web项目建立,手动生成web.xml文件
- Linux 中进程有哪几种状态?在 ps 显示出来的信息中, 分别用什么符号表示的?
1.不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的.不可中断, 指进程不响应异步信号. 第 441 页 共 485 页2.暂停状态/跟踪状态:向进程发送一个 SIGSTOP 信号,它就会因响 ...
- HTTP-完整状态码表
HTTP状态码列表: 状态码 状态码英文名称 中文描述 100 Continue 继续.客户端应继续其请求 101 Switching Protocols 切换协议.服务器根据客户端的请求切换协议.只 ...
- C#ASP.NET网站开发步骤
1. 创建项目ASP.NET Web 应用程序. 2. 选择"Web 窗体"模板,然后单击 "确定" 按钮创建项目. 3. 在解决方案资源管理器中,右键添加we ...
- 关于根据数据反选checkbox
前两天完成了一个连接hbase数据库的mis系统,mis系统中经常需要修改功能,复选框.多选框等等的自动勾选,感觉很麻烦,在此记录一下修改功能checkbox自动选中. 例子: <div cla ...