仿小米运动的蓝牙开源项目(附详细实现说明+源码)

托瓦兹 莱纳斯 是一个天才.
这个项目主要以蓝牙和自己diy的手环连接,可以记录测试数据,绘制成折线坐标图之类的功能.

这里写图片描述

这里写图片描述

项目结构很简单
这里写图片描述
6个类,其中AcceptThread,ConnectedThread,为线程工具类.只有两个界面活动类,分别是MainActivity,DataActivity;然后ViewHandler 是为了实现异步改变UI , CircleTextView是我自定义的TextView.

大概思路是 通过 AcceptThread 连接 蓝牙设备 ,ConnectedThread 建立流通信.然后收到信息后 用本地广播 LocalBroadcast 进行本地全局 , 再触发 handler 来更改ui .

主界面那个转圈的小球用的是动画 animation 为了保证以某一圆心 旋转,所以其实 旋转的是一个 framlayout.而圆点 是一个位于framlayout左中间的button哈哈.
关于曲线坐标图,我用了一个挺不错的框架.https://github.com/QQ951127336/SmallChart

项目源码
https://github.com/QQ951127336/Bluetooth-Assistant

注:android5.0后小变化
需添加权限
android.permission.ACCESS_COARSE_LOCATION
贴代码了

MainActivity

package com.tree.max.assistant;

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.Handler;
import android.os.Message;
import android.support.design.widget.Snackbar;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.ContentFrameLayout;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import java.util.Set;

public class MainActivity extends AppCompatActivity {

    final int NUMBER_CHANGED=1;//用来判断是否接到数据
    TextView numberView;
    final String name = "HC-06";//设备名字
    LinearLayout liitleButton ;
    FrameLayout contentFrameLayout ;
    Button startBuletooth,connectBlueTooth,dataButton;
    BluetoothAdapter bluetoothAdapter;
    ArrayAdapter<String> arrayAdapter ;
    ListView listView;
    BroadcastReceiver receiver;
    String number = "0";
    LocalReceiver localReceiver;
    int i  = 0;

    final Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case NUMBER_CHANGED:
                    numberView.setText(number);//更改UI数据
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_new);
        init();
        circle();


//        arrayAdapter = new ArrayAdapter<String>(MainActivity.this,R.layout.list_item);
        listView.setAdapter(arrayAdapter);

        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//蓝牙适配器

        if (bluetoothAdapter == null)
        {
            Snackbar.make(startBuletooth,"You have no bluetooth",Snackbar.LENGTH_INDEFINITE).show();
        }

        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (BluetoothDevice.ACTION_FOUND.equals(action))
                {
                    BluetoothDevice device =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                   // arrayAdapter.add(device.getName()+ " : "+device.getAddress());

                 if (device.getName().equals(name)) {
                     findDevice(device);
                     Log.e("device",device.getName());
                 }
                }
            }
        };

        IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);//找到设备发出广播
        registerReceiver(receiver,intentFilter);






    }
    @Override
    public void onResume()
    {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("LOCAL_BROAD_EV_PROGRESS");//本地UI线程广播
        localReceiver= new LocalReceiver();
        LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);


    }
    @Override
    public void onPause()
    {
        super.onPause();

    }
    public void findDevice(BluetoothDevice device)
    {
        if (device.getName().equals(name))
        {
            Log.e("device","find");
            if (bluetoothAdapter.isDiscovering())
            {
                bluetoothAdapter.cancelDiscovery();
            }
            AcceptThread acceptThread = new AcceptThread(device,MainActivity.this);
            acceptThread.start();
        }

    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
        unregisterReceiver(localReceiver);

    }


    private void init(){
        numberView = (TextView)findViewById(R.id.numberTextView);
        liitleButton = (LinearLayout) findViewById(R.id.little_circle);
        contentFrameLayout = (FrameLayout) findViewById(R.id.contentLayout);
        startBuletooth = (Button)findViewById(R.id.startBluetooth);
        connectBlueTooth = (Button)findViewById(R.id.connectBluetooth);
        dataButton = (Button)findViewById(R.id.dataButton);
        listView = (ListView)findViewById(R.id.listView);

        ClickListener clickListener = new ClickListener();
        startBuletooth.setOnClickListener(clickListener);
        connectBlueTooth.setOnClickListener(clickListener);
        dataButton.setOnClickListener(clickListener);







    }

    public void circle()
    {
        Animation sanimation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.circle_anim);
        liitleButton.startAnimation(sanimation);
        sanimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                circle();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

    }
    class ClickListener implements View.OnClickListener {

        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.startBluetooth://开启蓝牙
                    if (!bluetoothAdapter.isEnabled())
                    {
                        int REQUEST_ENABLE_BT = 1;
                        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                        startActivityForResult(intent,REQUEST_ENABLE_BT);
                    }

                    break;
                case R.id.connectBluetooth://扫描,连接设备
                    if (bluetoothAdapter.isDiscovering()) {
                        bluetoothAdapter.cancelDiscovery();
                        i = 0;

                    }
                    bluetoothAdapter.startDiscovery();
                    break;
                case R.id.dataButton://进入数据界面
                    Intent intent = new Intent(MainActivity.this,DataActivity.class);
                    startActivity(intent);






            }
        }
    }
    private class LocalReceiver extends BroadcastReceiver{//本地ui控制广播

        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction())
            {
                case "LOCAL_BROAD_EV_PROGRESS":
                    Bundle bundle = intent.getExtras();
                    number = bundle.getString("Times");
                    Message msg =new Message();
                    msg.what =NUMBER_CHANGED;
                    handler.sendMessage(msg);
                    i++;
                    if (i==1)
                    {
                        Snackbar.make(startBuletooth,"已连接到手环",Snackbar.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    }


}

DataActivity

package com.tree.max.assistant;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;

import com.idtk.smallchart.chart.LineChart;
import com.idtk.smallchart.data.LineData;
import com.idtk.smallchart.interfaces.iData.ILineData;

import java.util.ArrayList;

/**
 * Created by max on 17-5-18.
 */

public class DataActivity extends Activity {
    LineChart lineChart;
    LineData lineData;
    ArrayList<ILineData> dataList;
    ArrayList<PointF> linePointList ;
    LocalReceiver localReceiver;
    int[] x = new int[10];
    int[] y = new int[10];
    final int NUMBER_CHANGED = 1;
    String number;


    final Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case NUMBER_CHANGED:
                    lineChart.setDataList(dataList);
                    break;
            }
        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.data_view);
        init();


        linePointList.add(new PointF(1,2));
        linePointList.add(new PointF(10,10));
        linePointList.add(new PointF(100,100));
        linePointList.add(new PointF(200,200));
        lineData.setValue(linePointList);
        lineData.setColor(Color.CYAN);
        lineData.setPaintWidth(1);
        lineData.setTextSize(4);
        dataList.add(lineData);

        lineChart.isAnimated = false;
        lineChart.setDataList(dataList);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("LOCAL_BROAD_EV_PROGRESS");
        localReceiver= new LocalReceiver();
        LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(localReceiver);
    }

    public void init()
    {
        lineChart = (LineChart)findViewById(R.id.times_data_view);
        lineData = new LineData();
        linePointList = new ArrayList<>();
        dataList = new ArrayList<>();

        for (int j= 0; j<10;j++)
        {
            x[j] = j*10;
        }
    }
    private class LocalReceiver extends BroadcastReceiver
    {

        @Override
        public void onReceive(Context context, Intent intent) {
            switch(intent.getAction()) {
                case "LOCAL_BROAD_EV_PROGRESS":
                    Bundle bundle = intent.getExtras();
                    number = bundle.getString("Times");
                    for (int i = 1;i<=9;i++)
                    {
                        x[i-1] = x[i];
                        y[i-1] = y[i];
                    }
                    x[9] = 10;
                    y[9] = 10;
                    linePointList.clear();
                    for (int i = 0 ; i<10;i++)
                    {
                        linePointList.add(new PointF(x[i],y[i]));
                    }
                    lineData.setValue(linePointList);
                    dataList.clear();
                    dataList.add(lineData);
                    Message msg =new Message();
                    msg.what =NUMBER_CHANGED;
                    handler.sendMessage(msg);

            }
        }
    }
}

AcceptThread

package com.tree.max.assistant;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.support.design.internal.NavigationMenu;
import android.util.Log;
import android.widget.TextView;

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

/**
 * Created by max on 17-5-17.
 */

public class AcceptThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    private Context context;
    private final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    public AcceptThread(BluetoothDevice device,Context context) {
        // Use a temporary object that is later assigned to mmSocket,
        // because mmSocket is final
        Log.e("AcceptThread","start");
        BluetoothSocket tmp = null;
        mmDevice = device;
        this.context = context;

        // Get a BluetoothSocket to connect with the given BluetoothDevice
        try {
            // MY_UUID is the app's UUID string, also used by the server code
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        } catch (IOException e) { }
        mmSocket = tmp;
    }

    public void run() {
        // Cancel discovery because it will slow down the connection
//        mBluetoothAdapter.cancelDiscovery();

        try {
            // Connect the device through the socket. This will block
            // until it succeeds or throws an exception
            mmSocket.connect();
        } catch (IOException connectException) {
            // Unable to connect; close the socket and get out
            try {
                mmSocket.close();
            } catch (IOException closeException) { }
            return;
        }

        // Do work to manage the connection (in a separate thread)
        manageConnectedSocket(mmSocket);
    }

    /** Will cancel an in-progress connection, and close the socket */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }


    private void manageConnectedSocket(BluetoothSocket socket) {
        Log.e("AcceptThread","finished");
        ConnectedThread connectedThread = new ConnectedThread(socket,context);
        connectedThread.start();
    }


}

ConnectedThread

package com.tree.max.assistant;

import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.TextView;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.os.Handler;

/**
 * Created by max on 17-5-17.
 */

public class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
    Handler mHandler;
    Message message;
    Bundle bundle;
    LocalBroadcastManager localBroadcastManager;
    Intent intent = new Intent("LOCAL_BROAD_EV_PROGRESS");


    public ConnectedThread(BluetoothSocket socket,Context context) {

        localBroadcastManager = LocalBroadcastManager.getInstance(context);
        Log.e("ConnectedThread","start");
        message = new Message();
        bundle = new Bundle();
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;


        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) { }

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()

        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.read(buffer);
                // Send the obtained bytes to the UI activity
                String str = new String(buffer, "ISO-8859-1");
                str = str.substring(0, bytes);
                Log.e("recv", str);
                Bundle bundle = new Bundle();
                bundle.putString("Times",str);
                intent.putExtras(bundle);
                localBroadcastManager.sendBroadcast(intent);



            } catch (IOException e) {
                break;
            }
        }
    }

    /* Call this from the main activity to send data to the remote device */
    public void write(byte[] bytes) {
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) { }
    }

    /* Call this from the main activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) { }
    }

}

ViewHandler

package com.tree.max.assistant;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

/**
 * Created by max on 17-5-17.
 */

public class ViewHandler extends Handler {
    public ViewHandler()
    {
    }
    public ViewHandler(Looper looper)
    {
        super(looper);
    }
    @Override
    public void handleMessage(Message msg)
    {
        super.handleMessage(msg);
        Bundle b = msg.getData();
        String times =b.getString("Size");
        sendMessage(msg);
    }
}
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页