前言:

  最近接触蓝牙开发,主要是通过蓝牙连接获取传感器硬件设备的数据,并进行处理。

  网上学习一番,现整理出一套比较标准的 操作流程代码。

  如果大家看得懂,将来只需要改下 硬件设备的MAC码 和 改下对接收数据的处理 即可。  一切都是套路~~~

现在以一个小型项目需求来学习Android蓝牙编程

需求: 通过蓝牙获取硬件数据,并显示在一个随数据即时变化的动态折线图中。

实现思路:

(1) 配对蓝牙设备

(2) 连接蓝牙设备    ,根据MAC地址,代码中修改

(3) 接收数据

(4) 处理数据          ,根据硬件厂商提供给你的数据转换公式,在BluetoothService类中 修改

(5) 传数据给折线图,展现实时变化

-----------------------------------------------------------------------

蓝牙知识了解:

(1)、MAC地址:每个设备都有全球唯一的,根据此MAC地址判断蓝牙设备

(2)、蓝牙传输数据,通常一秒钟会传输很多个包,每个包的数据情况如下:

  此时,这个包有11个字节,0x55 是首码,通常通过他来判断一个包的开始

                                     SUM是验证码,会有一套公式来计算,判断当前包是不是一个有效的完整的包

              中间的即是数据,然后硬件方面会给我们一套计算公式,可以以此获取我们要的数据。

  当然每个硬件的包的数据大小都是不同的,有的可能有21个字节,每个硬件的数据的计算方式也不想同

代码实现:

一共就三部分,因为代码篇幅可能较大,不适合一段段代码讲解,直接贴出整个代码。所有的解释都在注释当中。

其中:

(1)、红色部分是需要大家根据个人硬件情况进行修改的

(2)、紫色部分是根据个人数据情况添加删除修改的。

一:MainActivity

public class MainActivity extends Activity {private BluetoothService mBluetoothService; //自定义蓝牙服务类private BluetoothAdapter mBluetoothAdapter;private String mConnectedDeviceName = null; //连接设备的名称//默认是1,因为程序启动时首先会连接一个蓝牙private int current_pos = 1;//hanlder消息标识 message.whatpublic 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;         // Toast//传感器 ,这里默认同时需要和三个硬件连接,分别设置id 1,2,3进行区分,demo中实际只用到 MAGIKARE_SENSOR_DOWN = 1//可以根据情况自行添加删除public static final int MAGIKARE_SENSOR_UP = 2;public static final int MAGIKARE_SENSOR_DOWN = 1;public static final int MAGIKARE_SENSOR_CENTER = 3;public static float[] m_receive_data_up;                    //传感器的数据public static float[] m_receive_data_down;                  //传感器的数据 ,demo中我们只需要这一个,因为只有一个硬件设备,public static float[] m_receive_data_center;                //传感器的数据
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取蓝牙适配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 1、判断设备是否支持蓝牙功能if (mBluetoothAdapter == null) {//设备不支持蓝牙功能Toast.makeText(this, "当前设备不支持蓝牙功能!", Toast.LENGTH_SHORT).show();return;}// 2、打开设备的蓝牙功能if (!mBluetoothAdapter.isEnabled()) {boolean enable = mBluetoothAdapter.enable(); //返回值表示 是否成功打开了蓝牙设备if (enable) {Toast.makeText(this, "打开蓝牙功能成功!", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "打开蓝牙功能失败,请到'系统设置'中手动开启蓝牙功能!", Toast.LENGTH_SHORT).show();return;}}// 3、创建自定义蓝牙服务对象if (mBluetoothService == null) {mBluetoothService = new BluetoothService(MainActivity.this, mHandler);}if (mBluetoothService != null) {//根据MAC地址远程获取一个蓝牙设备,这里固定了,实际开发中,需要动态设置参数(MAC地址)BluetoothDevice sensor_down = mBluetoothAdapter.getRemoteDevice("20:16:06:15:78:76");if (sensor_down != null) {//成功获取到远程蓝牙设备(传感器),这里默认只连接MAGIKARE_SENSOR_DOWN = 1这个设备
                mBluetoothService.connect(sensor_down, MAGIKARE_SENSOR_DOWN);}}}private Handler mHandler = new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {switch (msg.what){case MESSAGE_READ:try {String str=msg.getData().getString("index");int index=Integer.valueOf(str);switch (index){//获取到蓝牙传输过来的数据case MAGIKARE_SENSOR_UP:m_receive_data_up=msg.getData().getFloatArray("Data");break;//实际只用到这个case ,因为demo只连接了一个硬件设备case MAGIKARE_SENSOR_DOWN:m_receive_data_down=msg.getData().getFloatArray("Data");break;case MAGIKARE_SENSOR_CENTER:m_receive_data_center=msg.getData().getFloatArray("Data");break;}} catch (Exception e) {// TODO: handle exception
                    }break;case MESSAGE_STATE_CHANGE:
//                    连接状态switch (msg.arg1) {case BluetoothService.STATE_CONNECTED:break;case BluetoothService.STATE_CONNECTING:break;case BluetoothService.STATE_LISTEN:break;case BluetoothService.STATE_NONE:break;}break;case MESSAGE_DEVICE_NAME:mConnectedDeviceName = msg.getData().getString("device_name");Log.i("bluetooth","成功连接到:"+mConnectedDeviceName);Toast.makeText(getApplicationContext(),"成功连接到设备" + mConnectedDeviceName,Toast.LENGTH_SHORT).show();break;case MESSAGE_TOAST:int index=msg.getData().getInt("device_id");Toast.makeText(getApplicationContext(),msg.getData().getString("toast"), Toast.LENGTH_SHORT).show();//当失去设备或者不能连接设备时,重新连接Log.d("Magikare","当失去设备或者不能连接设备时,重新连接");            //重新连接硬件设备if(mBluetoothService!=null){switch (index) {case MAGIKARE_SENSOR_DOWN:                    //根据你的硬件的MAC地址写参数,每一个硬件设备都有一个MAC地址,此方法是根据MAC地址得到蓝牙设备BluetoothDevice sensor_down = mBluetoothAdapter.getRemoteDevice("20:16:06:15:78:76");if (sensor_down != null)mBluetoothService.connect(sensor_down, MAGIKARE_SENSOR_DOWN);break;case MAGIKARE_SENSOR_UP:BluetoothDevice sensor_up = mBluetoothAdapter.getRemoteDevice("");  //参数写你这个设备的MAC码if (sensor_up != null)mBluetoothService.connect(sensor_up, MAGIKARE_SENSOR_UP);break;case MAGIKARE_SENSOR_CENTER:BluetoothDevice center = mBluetoothAdapter.getRemoteDevice("");    //参数写你这个设备的MAC码if (center != null)mBluetoothService.connect(center, MAGIKARE_SENSOR_CENTER);break;}}break;}return false;}});public synchronized void onResume() {super.onResume();if (mBluetoothService != null) {if (mBluetoothService.getState() == BluetoothService.STATE_NONE) {mBluetoothService.start();}}}@Overridepublic void onDestroy() {super.onDestroy();if (mBluetoothService != null) mBluetoothService.stop();}    // 硬件通过蓝牙传输的byte类型已经转换为float类型,并且通过handler传输到 m_receive_data_down[]数组中,一下操作是获取这个数据,根据个人情况使用//获取角度public float[] GetAngle(int index){float[] angles=new float[3];if(m_receive_data_up==null||m_receive_data_down==null){return angles;}switch (index){case  MAGIKARE_SENSOR_DOWN:angles[0]=m_receive_data_down[6];angles[1]=m_receive_data_down[7];angles[2]=m_receive_data_down[8];break;case MAGIKARE_SENSOR_UP:angles[0]=m_receive_data_up[6];angles[1]=m_receive_data_up[7];angles[2]=m_receive_data_up[8];Log.d("安卓 Up 角度",angles[0]+","+angles[1]+","+angles[2]);break;}return angles;}//获取角速度public static float[] GetAngleSpeed(int index){float [] anglespeed=new float[3];if(m_receive_data_down==null){return anglespeed;}switch (index){case MAGIKARE_SENSOR_DOWN:anglespeed[0]=m_receive_data_down[3];anglespeed[1]=m_receive_data_down[4];anglespeed[2]=m_receive_data_down[5];break;case MAGIKARE_SENSOR_UP:anglespeed[0]=m_receive_data_up[3];anglespeed[1]=m_receive_data_up[4];anglespeed[2]=m_receive_data_up[5];break;}return  anglespeed;}public float[] GetQuaternion(int index){float[] quaternion=new float[4];if(m_receive_data_down==null){return quaternion;}switch (index){case  MAGIKARE_SENSOR_DOWN:quaternion[0]=m_receive_data_down[23];quaternion[1]=m_receive_data_down[24];quaternion[2]=m_receive_data_down[25];quaternion[3]=m_receive_data_down[26];Log.i("saveinfo","m_receive_data_down23"+m_receive_data_down[23]);Log.i("saveinfo","m_receive_data_down24"+m_receive_data_down[24]);Log.i("saveinfo","m_receive_data_down25"+m_receive_data_down[25]);Log.i("saveinfo","m_receive_data_down26"+m_receive_data_down[26]);break;case MAGIKARE_SENSOR_UP:quaternion[0]=m_receive_data_up[23];quaternion[1]=m_receive_data_up[24];quaternion[2]=m_receive_data_up[25];quaternion[3]=m_receive_data_up[26];break;case MAGIKARE_SENSOR_CENTER:quaternion[0]=m_receive_data_center[23];quaternion[1]=m_receive_data_center[24];quaternion[2]=m_receive_data_center[25];quaternion[3]=m_receive_data_center[26];}return  quaternion;}}

二、BluetoothService

public class BluetoothService {  private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");private Context context;//蓝牙适配器private BluetoothAdapter mAdapter;private Handler mHandler;//当前传感器设备的个数,即要开启的线程个数,用于设置线程数组的大小//这里默认为1,因为我们目前只需要和一个传感器连接, 比如:你要连接两个硬件设备,那就设置值为2,这样就会开启两个线程,分别去执行想要操作public static final int  SENSEOR_NUM=1;private AcceptThread mAcceptThread;// 请求连接的监听进程private ConnectThread mConnectThread;// 连接一个设备的进程public ConnectedThread[] mConnectedThread=new ConnectedThread[SENSEOR_NUM];// 已经连接之后的管理进程private int mState;// 当前状态// 指明连接状态的常量public static final int STATE_NONE = 0;         //没有连接public static final int STATE_LISTEN = 1;       //等待连接public static final int STATE_CONNECTING = 2;  //正在连接public static final int STATE_CONNECTED = 3;   //已经连接public BluetoothService(Context context, Handler mHandler) {this.context = context;this.mHandler = mHandler;mAdapter = BluetoothAdapter.getDefaultAdapter();//获取蓝牙适配器mState = STATE_NONE ; //当前连接状态:未连接
    }// 参数 index 是 硬件设备的id ,随便设的,目的在于当 同时连接多个硬件设备的时候,根据此id进行区分public synchronized void connect(BluetoothDevice device, int index) {//连接一个蓝牙时,将该设备 的蓝牙连接线程关闭,如果有的话//demo  就只有一个硬件设备,默认该设备id 取值index=1;if (mConnectedThread[index-1] != null) {mConnectedThread[index-1].cancel();mConnectedThread[index-1]=null;}mConnectThread=new ConnectThread(device,index);mConnectThread.start();setState(STATE_CONNECTING);}private class ConnectThread extends Thread{private final BluetoothSocket mmSocket;private final BluetoothDevice mmDevice;private int index;public ConnectThread(BluetoothDevice device,int index) {mmDevice = device;this.index=index;BluetoothSocket tmp = null;try {tmp = device.createRfcommSocketToServiceRecord(MY_UUID);// Get a BluetoothSocket for a connection with the given BluetoothDevice
            }catch (IOException e) {}mmSocket = tmp;}public void run() {setName("ConnectThread");//当连接成功,取消蓝牙适配器搜索蓝牙设备的操作,因为搜索操作非常耗时mAdapter.cancelDiscovery();// Always cancel discovery because it will slow down a connectiontry {mmSocket.connect();// This is a blocking call and will only return on a successful connection or an exception
            }catch (IOException e) {connectionFailed(this.index);try {mmSocket.close();} catch (IOException e2) {}BluetoothService.this.start();// 引用来说明要调用的是外部类的方法 runreturn;}synchronized (BluetoothService.this) {// Reset the ConnectThread because we're donemConnectThread = null;}connected(mmSocket, mmDevice,index);// Start the connected thread
        }public void cancel() {try {mmSocket.close();} catch (IOException e) {}}}class ConnectedThread extends Thread{private BluetoothSocket mmSocket;private InputStream mmInStream;private OutputStream mmOutStream;private int index;private Queue<Byte> queueBuffer = new LinkedList<Byte>();private byte[] packBuffer = new byte[11];//构造方法public ConnectedThread(BluetoothSocket socket,int index) {mmSocket = socket;InputStream tmpIn = null;OutputStream tmpOut = null;this.index=index;// Get the BluetoothSocket input and output streamstry {tmpIn = socket.getInputStream();tmpOut = socket.getOutputStream();} catch (IOException e) {}mmInStream = tmpIn;mmOutStream = tmpOut;}// 数组大小看你的数据需求,这里存的是你处理蓝牙传输来的字节数据之后实际要用到的数据private float [] fData=new float[31];@Overridepublic void run() {byte[] tempInputBuffer = new byte[1024];int acceptedLen = 0; //记录每次读取数据的数据长度byte sHead;long lLastTime = System.currentTimeMillis(); //获取开始时间while(true){try {acceptedLen = mmInStream.read(tempInputBuffer);//返回接收的长度//从缓冲区中读取数据for (int i = 0; i < acceptedLen; i++) {queueBuffer.add(tempInputBuffer[i]);}// 这里需要按个人硬件数据的情况自行修改了// 如果你的硬件蓝牙传输 一个包有11个字节,那queueBuffer.size()>=11// 如果你的硬件蓝牙传输 一个包有21个字节,那queueBuffer.size()>=21while (queueBuffer.size()>=11){//返回队首并删除,判断队首是不是0x55,如果不是,说明不是一个包的数据,跳过,//注意这里的0x55是你的包的首字节 if (queueBuffer.poll()!=0x55)continue;// 进入到这里,说明得到一个包的数据了,然后就要根据个人硬件的数据情况,将byte类型的数据转换为float类型的数据sHead = queueBuffer.poll(); //返回队首并删除                      // 现在得到的就是你数据部分了,如果有9位字节代表数据,j<9 ,如果有19位字节代表数据,j<19                               //将字节数组存到packBuffer[]数据中,用于byte-->float数据的转换 for (int j = 0; j < 9; j++) {packBuffer[j] = queueBuffer.poll();}switch (sHead) {//case 0x52://角速度fData[3] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) /  2000;fData[4] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) /  200;fData[5] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) /  200;fData[17] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) / 100.0f;break;case 0x53://角度fData[6] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) /  180;fData[7] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) /  180;fData[8] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) /  180;fData[17] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) / 100.0f;break;case 0x59://四元数fData[23] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) / 327.0f;fData[24] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) /327.0f;fData[25] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) /327.0f;fData[26] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) /327.0f;break;}}long lTimeNow = System.currentTimeMillis(); // 获取收据转换之后的时间// 如果数据处理后的时间  与 接收到数据的时间 的时间差>80 则发送消息传输数据,// 这个时间需要看你硬件一秒钟发送的包的个数if (lTimeNow - lLastTime > 80) {lLastTime = lTimeNow;Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_READ);Bundle bundle = new Bundle();bundle.putString("index",String.valueOf(this.index));bundle.putFloatArray("Data", fData);msg.setData(bundle);mHandler.sendMessage(msg);}} catch (IOException e) {connectionLost(this.index);e.printStackTrace();}}}public void cancel() {try {mmSocket.close();} catch (IOException e) {}}}//连接失败private void connectionFailed(int index) {setState(STATE_LISTEN);// Send a failure message back to the ActivityMessage msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString("toast", "未能连接设备"+index);bundle.putInt("device_id",index);msg.setData(bundle);mHandler.sendMessage(msg);}// 连接丢失private void connectionLost(int index) {setState(STATE_LISTEN);Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);Bundle bundle = new Bundle();bundle.putString("toast", "设备丢失"+index);bundle.putInt("device_id",index);msg.setData(bundle);mHandler.sendMessage(msg);}//用于 蓝牙连接的Activity onResume()方法public synchronized void start() {// Cancel any thread attempting to make a connectionif (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}if (mAcceptThread == null) {mAcceptThread = new AcceptThread();mAcceptThread.start();}setState(STATE_LISTEN);}public synchronized void connected(BluetoothSocket socket,BluetoothDevice device,int index) {Log.d("MAGIKARE","连接到线程"+index);// Cancel the thread that completed the connectionif (mConnectThread != null) {mConnectThread.cancel();mConnectThread = null;}// Cancel the accept thread because we only want to connect to one deviceif (mAcceptThread != null) {mAcceptThread.cancel();mAcceptThread = null;}// Start the thread to manage the connection and perform transmissionsmConnectedThread[index-1] = new ConnectedThread(socket,index);mConnectedThread[index-1].start();// Send the name of the connected device back to the UI ActivityMessage msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);Bundle bundle = new Bundle();bundle.putString("device_name", device.getName()+" "+index);msg.setData(bundle);mHandler.sendMessage(msg);setState(STATE_CONNECTED);}private synchronized void setState(int state) {mState = state;// Give the new state to the Handler so the UI Activity can updatemHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();}private class AcceptThread extends Thread {// The local server socketprivate final BluetoothServerSocket mmServerSocket;//private int index;public AcceptThread() {BluetoothServerSocket tmp = null;// this.index=index;// Create a new listening server sockettry {tmp = mAdapter.listenUsingRfcommWithServiceRecord("BluetoothData", MY_UUID);}catch (IOException e) {}mmServerSocket = tmp;}public void run() {new Thread(new Runnable() {@Overridepublic void run() {}}).start();}public void cancel() {try {if(mmServerSocket!=null) {mmServerSocket.close();}}catch (IOException e) {}}}public synchronized int getState() {return mState;}public synchronized void stop() {if (mConnectedThread != null) {for(int i=0;i<mConnectedThread.length;i++){mConnectedThread[i].cancel();}mConnectedThread = null;}if (mAcceptThread != null) {mAcceptThread.cancel();mAcceptThread = null;}setState(STATE_NONE);}
}

三、自定义即时变化的折线图:

public class MyView extends View {/*http://www.cnblogs.com/aibuli/p/950c34f2bc0d02cbd290dd6a8339d42a.html*///坐标轴原点的位置private int xPoint=60;private int yPoint=260;//刻度长度private int xScale=8;  //8个单位构成一个刻度private int yScale=40;//x与y坐标轴的长度private int xLength=580;private int yLength=480;private int MaxDataSize=xLength/xScale;   //横坐标  最多可绘制的点private List<Float> data=new ArrayList<Float>();   //存放 纵坐标 所描绘的点private String[] yLabel=new String[yLength/yScale];  //Y轴的刻度上显示字的集合private Handler mh=new Handler(){public void handleMessage(android.os.Message msg) {if(msg.what==0){                //判断接受消息类型MyView.this.invalidate();  //刷新View
            }};};public MyView(Context context, AttributeSet attrs) {super(context, attrs);for (int i = 0; i <yLabel.length; i++) {yLabel[i]=(i+1)+"M/s";}new Thread(new Runnable() {@Overridepublic void run() {while(true){     //在线程中不断往集合中增加数据try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}if(data.size()>MaxDataSize){  //判断集合的长度是否大于最大绘制长度data.remove(0);  //删除头数据
                    }// 这里得到蓝牙设备得到的数据float[] floats = MainActivity.GetAngleSpeed(1);data.add(floats[0]);mh.sendEmptyMessage(0);   //发送空消息通知刷新
                }}}).start();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint paint=new Paint();paint.setStyle(Paint.Style.STROKE);paint.setAntiAlias(true);paint.setColor(Color.RED);//绘制Y轴canvas.drawLine(xPoint, yPoint-yLength, xPoint, yPoint, paint);//绘制Y轴左右两边的箭头canvas.drawLine(xPoint, yPoint-yLength, xPoint-3,yPoint-yLength+6, paint);canvas.drawLine(xPoint, yPoint-yLength, xPoint+3,yPoint-yLength+6, paint);//Y轴上的刻度与文字for (int i = 0; i * yScale< yLength; i++) {canvas.drawLine(xPoint, yPoint-i*yScale, xPoint+5, yPoint-i*yScale, paint);  //刻度canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
        }//X轴canvas.drawLine(xPoint, yPoint, xPoint+xLength, yPoint, paint);//如果集合中有数据if(data.size()>1){for (int i = 1; i < data.size(); i++) {  //依次取出数据进行绘制canvas.drawLine(xPoint+(i-1)*xScale, yPoint-data.get(i-1)*yScale, xPoint+i*xScale, yPoint-data.get(i)*yScale, paint);}}}
}

相关知识:浅谈Bluetooth蓝牙开发

有问题欢迎留言交流!

转载于:https://www.cnblogs.com/xqxacm/p/5909716.html

Android项目实战(二十六):蓝牙连接硬件设备开发规范流程相关推荐

  1. Android项目实战(十六):QQ空间实现(一)—— 展示说说中的评论内容并有相应点击事件...

    大家都玩QQ空间客户端,对于每一个说说,我们都可以评论,那么,对于某一条评论: 白雪公主 回复 小矮人 : 你们好啊~ 我们来分析一下: 1.QQ空间允许我们 点击 回复人和被回复人的名字就可以进入对 ...

  2. Android 项目必备(十六)--> 手机号 验证码 密码

    文章目录 手机号 验证码 密码 在我们的项目中,获取验证码.手机号验证以及密码输入是很常见的小功能. 手机号 1. 布局文件 <EditTextandroid:id="@+id/et_ ...

  3. 应用程序框架实战二十六:查询对象

    信息系统的查询需求千变万化,在仓储中为每个查询需求创建一个特殊方法,将导致大量乏味而臃肿的接口. 一种更加可行的办法是,在应用层服务中描述查询需求,并通过仓储执行查询. 为了能够更好的描述查询需求,可 ...

  4. Spring boot 项目(二十六)——集成elasticsearch实现简单的书籍搜索

    前期准备 本地安装好es:安装教程 项目结构 代码编写 1.pom文件 <dependencies><!--springboot通用--><dependency>& ...

  5. Android项目实战(十五):自定义不可滑动的ListView和GridView

    不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView {public NoScrollListVi ...

  6. (转载)Android项目实战(二十七):数据交互(信息编辑)填写总结

    Android项目实战(二十七):数据交互(信息编辑)填写总结 前言: 项目中必定用到的数据填写需求.比如修改用户名的文字编辑对话框,修改生日的日期选择对话框等等.现总结一下,方便以后使用. 注: 先 ...

  7. android圆角对话框,Android项目实战(三十二):圆角对话框Dialog

    原文: Android项目实战(三十二):圆角对话框Dialog 前言:html 项目中多处用到对话框,用系统对话框太难看,就本身写一个自定义对话框.android 对话框包括:一.圆角程序员 二.a ...

  8. Vue + Spring Boot 项目实战(十五):动态加载后台菜单

    重要链接: 「系列文章目录」 「项目源码(GitHub)」 本篇目录 前言 一.后端实现 1.表设计 2.pojo 3.菜单查询接口(树结构查询) 二.前端实现 1.后台页面设计 2.数据处理 3.添 ...

  9. 【Android项目实战 | 从零开始写app(十二)】实现app首页智慧服务热门推荐热门主题、新闻

    说在前面,由于各种adapter,xml布局,bean实体类,Activity,也为了让看懂,代码基本都是"简单粗暴直接不好看",没啥okhttp和util工具类之类的封装,本篇幅 ...

最新文章

  1. Monitor Asynchronous Apex
  2. boost的chrono模块等待按键的测试程序
  3. PGM中置信传递、和—积算法
  4. android aar编程,AndroidStudio脚本命令指定AAR生成目录与版本号
  5. spring social_Spring Social入门
  6. 软件的可扩展性与框架的可交互性
  7. 坦克大战-C语言-详注版
  8. Python 爬取 201865 条《隐秘的角落》弹幕,发现看剧不如爬山?
  9. DL_C1_week4-1(Build Deep Neural Network)
  10. c语言正确声明的格式,c语言函数声明(c语言函数声明格式)
  11. 反馈抑制器使用场景与市场
  12. C语言之对 0, ‘0‘ , \0 以及 “0“ 的理解
  13. 文献综述在哪儿能找到?
  14. yolov7利用onnx进行推理同时调用usb摄像头
  15. SpringMVC @GetMapping注解路径冲突问题
  16. Controller层各注解总结
  17. 社区折腾日志:基于python搭建个人微信/支付宝免签支付功能
  18. Python笔记之用turtle库绘制三角函数和反三角函数的图像(考研党福利)
  19. allowMultiQueries 设置为true不生效问题
  20. 淘宝/天猫API:img2text-图片识别商品接口

热门文章

  1. 2020亚洲品牌500强榜单发布 ;肯德基中国门店将限时发售植物肉汉堡 | 美通企业日报...
  2. PHPMyWind支持ppt上传
  3. 【王道笔记-操作系统】第四章 文件管理
  4. yolov5训练常见错误解决办法
  5. 立创EDA布线使用技巧
  6. GitChat · 软件工程 | 一小时教你学会 Maven 项目的构建与管理
  7. pjsip安卓端编译步骤
  8. Java零基础必看学习教程,Java开发环境配置详解
  9. UOJ147 斗地主
  10. 计算机硬件交通灯课程设计,交通灯计算机硬件课程设计(附件).doc