android 藍牙開發(fā)

藍牙知識了解:

每個手機如果有藍牙的話,可以通過藍牙掃描到你手機的mac地址凯旭。

(1)、MAC地址:每個設備都有全球唯一的使套,根據(jù)此MAC地址判斷藍牙設備

(2)罐呼、藍牙傳輸數(shù)據(jù),通常一秒鐘會傳輸很多個包童漩,每個包的數(shù)據(jù)情況如下:

此時弄贿,這個包有11個字節(jié),0x55 是首碼矫膨,通常通過他來判斷一個包的開始

SUM是驗證碼差凹,會有一套公式來計算期奔,判斷當前包是不是一個有效的完整的包

中間的即是數(shù)據(jù),然后硬件方面會給我們一套計算公式危尿,可以以此獲取我們要的數(shù)據(jù)呐萌。

當然每個硬件的包的數(shù)據(jù)大小都是不同的,有的可能有21個字節(jié)谊娇,每個硬件的數(shù)據(jù)的計算方式也不想同.

代碼實現(xiàn):

一共就三部分肺孤,因為代碼篇幅可能較大,不適合一段段代碼講解济欢,直接貼出整個代碼赠堵。所有的解釋都在注釋當中。

一:MainActivity

  public class MainActivity extends Activity {

      private BluetoothService mBluetoothService; //自定義藍牙服務類
      private BluetoothAdapter mBluetoothAdapter;
      private String mConnectedDeviceName = null; //連接設備的名稱

      //默認是1,因為程序啟動時首先會連接一個藍牙
      private int current_pos = 1;

      //hanlder消息標識 message.what
      public static final int MESSAGE_STATE_CHANGE = 1; // 狀態(tài)改變
      public static final int MESSAGE_READ = 2;          // 讀取數(shù)據(jù)
      public static final int MESSAGE_WRITE = 3;         // 給硬件傳數(shù)據(jù)法褥,暫不需要茫叭,看具體需求
      public static final int MESSAGE_DEVICE_NAME = 4;  // 設備名字
      public static final int MESSAGE_TOAST = 5;         // Toast

  //傳感器 ,這里默認同時需要和三個硬件連接,分別設置id 1,2,3進行區(qū)分半等,demo中實際只用到 MAGIKARE_SENSOR_DOWN = 1
//可以根據(jù)情況自行添加刪除
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;                    //傳感器的數(shù)據(jù)
public static float[] m_receive_data_down;                  //傳感器的數(shù)據(jù) ,demo中我們只需要這一個揍愁,因為只有一個硬件設備,
public static float[] m_receive_data_center;                //傳感器的數(shù)據(jù)

@Override
protected 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, "打開藍牙功能失敗朽缎,請到'系統(tǒng)設置'中手動開啟藍牙功能!", Toast.LENGTH_SHORT).show();
            return;
        }
    }


    // 3蔚舀、創(chuàng)建自定義藍牙服務對象
    if (mBluetoothService == null) {
        mBluetoothService = new BluetoothService(MainActivity.this, mHandler);
    }
    if (mBluetoothService != null) {
        //根據(jù)MAC地址遠程獲取一個藍牙設備饵沧,這里固定了,實際開發(fā)中赌躺,需要動態(tài)設置參數(shù)(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() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what){
            case MESSAGE_READ:
                try {
                    String str=msg.getData().getString("index");
                    int index=Integer.valueOf(str);
                    switch (index)
                    {
                        //獲取到藍牙傳輸過來的數(shù)據(jù)
                        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:
                //連接狀態(tài)
                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:
          //根據(jù)你的硬件的MAC地址寫參數(shù),每一個硬件設備都有一個MAC地址缅叠,此方法是根據(jù)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("");  //參數(shù)寫你這個設備的MAC碼
                            if (sensor_up != null)
                                mBluetoothService.connect(sensor_up, MAGIKARE_SENSOR_UP);
                            break;
                        case MAGIKARE_SENSOR_CENTER:
                            BluetoothDevice center = mBluetoothAdapter.getRemoteDevice("");    //參數(shù)寫你這個設備的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();
        }
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mBluetoothService != null) mBluetoothService.stop();
}

      // 硬件通過藍牙傳輸?shù)腷yte類型已經(jīng)轉(zhuǎn)換為float類型悄泥,并且通過handler傳輸?shù)?m_receive_data_down[]數(shù)組中,一下操作是獲取這個數(shù)據(jù)肤粱,根據(jù)個人情況使用
      //獲取角度
      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;

      //當前傳感器設備的個數(shù),即要開啟的線程個數(shù)领曼,用于設置線程數(shù)組的大小
      //這里默認為1鸥鹉,因為我們目前只需要和一個傳感器連接蛮穿, 比如:你要連接兩個硬件設備,那就設置值為2毁渗,這樣就會開啟兩個線程践磅,分別去執(zhí)行想要操作
      public static final int  SENSEOR_NUM=1;

      private AcceptThread mAcceptThread;// 請求連接的監(jiān)聽進程
      private ConnectThread mConnectThread;// 連接一個設備的進程
      public ConnectedThread[] mConnectedThread=new ConnectedThread[SENSEOR_NUM];// 已經(jīng)連接之后的管理進程
      private int mState;// 當前狀態(tài)

      // 指明連接狀態(tài)的常量
      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;   //已經(jīng)連接

      public BluetoothService(Context context, Handler mHandler) {
      this.context = context;
      this.mHandler = mHandler;
      mAdapter = BluetoothAdapter.getDefaultAdapter();//獲取藍牙適配器
      mState = STATE_NONE ; //當前連接狀態(tài):未連接
      }

      // 參數(shù) index 是 硬件設備的id ,隨便設的灸异,目的在于當 同時連接多個硬件設備的時候府适,根據(jù)此id進行區(qū)分
      public synchronized void connect(BluetoothDevice device, int index) {

      //連接一個藍牙時,將該設備 的藍牙連接線程關(guān)閉肺樟,如果有的話
      //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 connection

        try {
            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();// 引用來說明要調(diào)用的是外部類的方法 run
            return;
        }

        synchronized (BluetoothService.this) {// Reset the ConnectThread because we're done
            mConnectThread = 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];


    //構(gòu)造方法
    public ConnectedThread(BluetoothSocket socket,int index) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        this.index=index;
        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {}

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    // 數(shù)組大小看你的數(shù)據(jù)需求喇聊,這里存的是你處理藍牙傳輸來的字節(jié)數(shù)據(jù)之后實際要用到的數(shù)據(jù)
    private float [] fData=new float[31];

    @Override
    public void run() {
        byte[] tempInputBuffer = new byte[1024];
        int acceptedLen = 0; //記錄每次讀取數(shù)據(jù)的數(shù)據(jù)長度
        byte sHead;
        long lLastTime = System.currentTimeMillis(); //獲取開始時間
        while(true){
            try {
                acceptedLen = mmInStream.read(tempInputBuffer);//返回接收的長度
                //從緩沖區(qū)中讀取數(shù)據(jù)
                for (int i = 0; i < acceptedLen; i++) {
                    queueBuffer.add(tempInputBuffer[i]);
                }
                // 這里需要按個人硬件數(shù)據(jù)的情況自行修改了
                // 如果你的硬件藍牙傳輸 一個包有11個字節(jié),那queueBuffer.size()>=11
                // 如果你的硬件藍牙傳輸 一個包有21個字節(jié)蹦狂,那queueBuffer.size()>=21
                while (queueBuffer.size()>=11){
                    //返回隊首并刪除,判斷隊首是不是0x55朋贬,如果不是凯楔,說明不是一個包的數(shù)據(jù),跳過锦募,
                    //注意這里的0x55是你的包的首字節(jié)
                    if (queueBuffer.poll()!=0x55)
                        continue;
                    // 進入到這里摆屯,說明得到一個包的數(shù)據(jù)了,然后就要根據(jù)個人硬件的數(shù)據(jù)情況糠亩,將byte類型的數(shù)據(jù)轉(zhuǎn)換為float類型的數(shù)據(jù)
                  sHead = queueBuffer.poll(); //返回隊首并刪除
    // 現(xiàn)在得到的就是你數(shù)據(jù)部分了虐骑,如果有9位字節(jié)代表數(shù)據(jù),j<9 赎线,如果有19位字節(jié)代表數(shù)據(jù)廷没,j<19
    //將字節(jié)數(shù)組存到packBuffer[]數(shù)據(jù)中,用于byte-->float數(shù)據(jù)的轉(zhuǎn)換
                    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)) / 32768.0f * 2000;
                            fData[4] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) / 32768.0f * 2000;
                            fData[5] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) / 32768.0f * 2000;
                            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)) / 32768.0f * 180;
                            fData[7] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) / 32768.0f * 180;
                            fData[8] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) / 32768.0f * 180;
                            fData[17] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) / 100.0f;
                            break;
                        case 0x59://四元數(shù)
                            fData[23] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) / 32768.0f;
                            fData[24] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff))/32768.0f;
                            fData[25] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff))/32768.0f;
                            fData[26] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff))/32768.0f;
                            break;
                    }
                }
                long lTimeNow = System.currentTimeMillis(); // 獲取收據(jù)轉(zhuǎn)換之后的時間
                // 如果數(shù)據(jù)處理后的時間  與 接收到數(shù)據(jù)的時間 的時間差>80 則發(fā)送消息傳輸數(shù)據(jù)垂寥,
                // 這個時間需要看你硬件一秒鐘發(fā)送的包的個數(shù)
                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 Activity
    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);
}
// 連接丟失
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 connection
    if (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 connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }
    // Cancel the accept thread because we only want to connect to one device
    if (mAcceptThread != null) {
        mAcceptThread.cancel();
        mAcceptThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread[index-1] = new ConnectedThread(socket,index);

    mConnectedThread[index-1].start();

    // Send the name of the connected device back to the UI Activity
    Message 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 update
    mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

private class AcceptThread extends Thread {
    // The local server socket
    private final BluetoothServerSocket mmServerSocket;
    //private int index;
    public AcceptThread() {
        BluetoothServerSocket tmp = null;
        // this.index=index;
        // Create a new listening server socket
        try {
            tmp = mAdapter.listenUsingRfcommWithServiceRecord("BluetoothData", MY_UUID);
        }
        catch (IOException e) {}
        mmServerSocket = tmp;
    }

    public void run() {
        new Thread(new Runnable() {
            @Override
            public 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個單位構(gòu)成一個刻度
    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() {
        @Override
        public void run() {
            while(true){     //在線程中不斷往集合中增加數(shù)據(jù)
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(data.size()>MaxDataSize){  //判斷集合的長度是否大于最大繪制長度
                    data.remove(0);  //刪除頭數(shù)據(jù)
                }
                // 這里得到藍牙設備得到的數(shù)據(jù)
                float[] floats = MainActivity.GetAngleSpeed(1);
                data.add(floats[0]);
                mh.sendEmptyMessage(0);   //發(fā)送空消息通知刷新
            }
        }
    }).start();
}

@Override
protected 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);
    //如果集合中有數(shù)據(jù)
    if(data.size()>1){
        for (int i = 1; i < data.size(); i++) {  //依次取出數(shù)據(jù)進行繪制
            canvas.drawLine(xPoint+(i-1)*xScale, yPoint-data.get(i-1)*yScale, xPoint+i*xScale, yPoint-data.get(i)*yScale, paint);
        }
    }
  }}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市滞项,隨后出現(xiàn)的幾起案子狭归,更是在濱河造成了極大的恐慌,老刑警劉巖文判,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件过椎,死亡現(xiàn)場離奇詭異,居然都是意外死亡戏仓,警方通過查閱死者的電腦和手機疚宇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門亡鼠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人灰嫉,你說我怎么就攤上這事拆宛。” “怎么了讼撒?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵浑厚,是天一觀的道長。 經(jīng)常有香客問我根盒,道長钳幅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任炎滞,我火速辦了婚禮敢艰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘册赛。我一直安慰自己钠导,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布森瘪。 她就那樣靜靜地躺著牡属,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扼睬。 梳的紋絲不亂的頭發(fā)上逮栅,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音窗宇,去河邊找鬼措伐。 笑死,一個胖子當著我的面吹牛军俊,可吹牛的內(nèi)容都是我干的侥加。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼粪躬,長吁一口氣:“原來是場噩夢啊……” “哼官硝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起短蜕,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤氢架,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朋魔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岖研,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了孙援。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片害淤。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拓售,靈堂內(nèi)的尸體忽然破棺而出窥摄,到底是詐尸還是另有隱情,我是刑警寧澤础淤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布崭放,位于F島的核電站,受9級特大地震影響鸽凶,放射性物質(zhì)發(fā)生泄漏币砂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一玻侥、第九天 我趴在偏房一處隱蔽的房頂上張望决摧。 院中可真熱鬧,春花似錦凑兰、人聲如沸掌桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拘鞋。三九已至,卻和暖如春矢门,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背灰蛙。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工祟剔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人摩梧。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓物延,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仅父。 傳聞我的和親對象是個殘疾皇子叛薯,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容