根据相关代码制作了一个开源依赖包,将以下所有的代码进行打包,直接调用即可完成所有的操作。详细说明地址如下,如果觉得有用可以GIthub点个Star支持一下:

项目官网
Kotlin版本说明文档
Java版本说明文档

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源码下载)的更多相关文章

  1. Asp.net MVC集成Google Calendar API(附Demo源码)

    Asp.net MVC集成Google Calendar API(附Demo源码) Google Calendar是非常方便的日程管理应用,很多人都非常熟悉.Google的应用在国内不稳定,但是在国外 ...

  2. winserver的consul部署实践与.net core客户端使用(附demo源码)

    winserver的consul部署实践与.net core客户端使用(附demo源码)   前言 随着微服务兴起,服务的管理显得极其重要.都知道微服务就是”拆“,把臃肿的单块应用,拆分成多个轻量级的 ...

  3. 近期热门微信小程序demo源码下载汇总

    近期微信小程序demo源码下载汇总,乃小程序学习分析必备素材!点击标题即可下载: 即速应用首发!原创!电商商场Demo 优质微信小程序推荐 -秀人美女图 图片下载.滑动翻页 微信小程序 - 新词 GE ...

  4. 物流一站式单号查询之快递鸟API接口(附Demo源码)

    连载篇提前看 物流一站式单号查询之快递鸟API接口 物流一站式查询之TrackingMore篇 物流一站式查询之顺丰接口篇 物流一站式查询之快递100 前情提要 前三篇中,我们已经从注册.申请接口.调 ...

  5. 基于spring-boot和docker-java实现对docker容器的动态管理和监控[附完整源码下载]

    ​ (我是个封面) docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,doc ...

  6. Android 二维码 生成和识别(附Demo源码)

    今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. Android.WP都有相关支持的软件.之前我就想了解二维码是如何工作,最近因为工作需要使用相关技 ...

  7. 【转】Android 二维码 生成和识别(附Demo源码)--不错

    原文网址:http://www.cnblogs.com/mythou/p/3280023.html 今天讲一下目前移动领域很常用的技术——二维码.现在大街小巷.各大网站都有二维码的踪迹,不管是IOS. ...

  8. .NET gRPC 核心功能初体验,附Demo源码

    gRPC是高性能的RPC框架, 有效地用于服务通信(不管是数据中心内部还是跨数据中心). 由Google开源,目前是一个Cloud Native Computing Foundation(CNCF)孵 ...

  9. 网络语音视频技术浅议(附多个demo源码下载)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...

随机推荐

  1. [XNUCA 进阶篇](web)writeup

    XNUCA 靶场练习题writeup default 阳关总在风雨后 题目过滤很多,*,#,/ ,and,or,|,union,空格,都不能用 盲注,最后的姿势是:1'%(1)%'1 中间的括号的位置 ...

  2. 查找goog13的ip

    C:\Users\Deen>ping 172.217.24.14 Pinging 172.217.24.14 with 32 bytes of data: Reply from 172.217. ...

  3. 题解0004:单词接龙(洛谷P1019)

    题目描述:已知一组单词,给定一个开头的字母,要求出以这个字母开头的最长的"龙"(每个单词都最多在"龙"中出现两次),在两个单词相连时,其重合部分合为一部分. 题 ...

  4. 在线Remix链接本地文件夹

    问题 1.本地Remix环境版本滞后于在线编译器,新版本的语法在旧版本编译器中出现错误. 2.没有配置Vscode编译器,不便导入项目. 解决方案 *本解决方案基于Mac系统 创建共享文件夹 在本地创 ...

  5. CF1553X Harbour.Space Scholarship Contest 2021-2022 (Div. 1 + Div. 2)

    掉大分 E 对于一个序列,把它排回去的最小次数是 $\sum置换环大小-1=错位个数-置换环个数$ 注意到m小于等于n/3.那么最多修正2m个错位.正确位置的个数必须大于等于n/3才可能在m次内修正. ...

  6. Eclipse建立Web项目,手动生成web.xml文件

    相关文章:https://blog.csdn.net/ys_code/article/details/79156188(Web项目建立,手动生成web.xml文件

  7. Linux 中进程有哪几种状态?在 ps 显示出来的信息中, 分别用什么符号表示的?

    1.不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的.不可中断, 指进程不响应异步信号. 第 441 页 共 485 页2.暂停状态/跟踪状态:向进程发送一个 SIGSTOP 信号,它就会因响 ...

  8. HTTP-完整状态码表

    HTTP状态码列表: 状态码 状态码英文名称 中文描述 100 Continue 继续.客户端应继续其请求 101 Switching Protocols 切换协议.服务器根据客户端的请求切换协议.只 ...

  9. C#ASP.NET网站开发步骤

    1. 创建项目ASP.NET Web 应用程序. 2. 选择"Web 窗体"模板,然后单击 "确定" 按钮创建项目. 3. 在解决方案资源管理器中,右键添加we ...

  10. 关于根据数据反选checkbox

    前两天完成了一个连接hbase数据库的mis系统,mis系统中经常需要修改功能,复选框.多选框等等的自动勾选,感觉很麻烦,在此记录一下修改功能checkbox自动选中. 例子: <div cla ...