0%

首先,进行一下科普:

1.BLE(Bluetooth Low Energy),蓝牙4.0核心profile,主要特点是快速搜索,快速连接,超低功耗保持连接和数据传输,缺点:数据传输速率低,由于其具有低功耗特点,故而经常用在可穿戴设备之中。Android4.3才开始支持BLE api。

2.关于BLE数据传输:

a.profile可以理解为一种规范,一个标准的通信协议,其存在于手机中,蓝牙组织规定了一些标准的profile:HID OVER GATT ,防丢器等,每个profile中包含了多个service。

b.service 可以理解为一个服务,在BLE从机中有多个服务,电量信息,系统服务信息等,每一个service中包含了多个characteristic特征值,每一个具体的characteristic特征值才是BLE通信的主题。

举个例子吧:从机当前的电量是80%,从机会借由电量的characteristic特征值将这个信息储存于从机的profile中,主机可以通过该characteristic来读取80%这个数据。

c.characteristic特征值:BLE主机从机通信均是通过characteristic进行,可以将其理解为一个标签,通过该标签可以读取或写入相关信息。

d. UUID(统一标识码):service和characteristic均需要这个唯一的UUID进行标识

/****************************************************************************************/

科普结束,首先上效果图:

 这个就是实现后的效果,我用的BLE模块是:MicrodunioBT4.0

/*********************************************************分隔符********************************************************************************/

BLE设备和Android应用进行通信,首先要做的就是让Android应用找到BLE设备(代码分析部分,只对关键点进行注释)

复制代码

package com.TANK.temperature.BT; import java.util.List; import com.TANK.temperature.R; import com.TANK.temperature.BT.BluetoothLeClass.OnDataAvailableListener; import com.TANK.temperature.BT.BluetoothLeClass.OnServiceDiscoverListener; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Typeface; import android.net.wifi.WifiConfiguration.Status; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.TextView; import android.widget.Toast; public class DeviceScanActivity extends Activity { private final static String TAG = DeviceScanActivity.class.getSimpleName(); private final static String UUID_KEY_DATA = “0000fff6-0000-1000-8000-00805f9b34fb”; private Handler mHandler; private static final long SCAN_PERIOD = 10000; /** 搜索BLE终端 */
private BluetoothAdapter mBluetoothAdapter; private BluetoothLeClass mBLE; private boolean mScanning; private BluetoothDevice BTtoLink = null; private String BTtoFind = “Microduino”; private TextView BT_find, BT_info, BT_link;//三个textview分别表示:设备是否找到,BLE模块传输的信息,连接状态
private String S_BT_info = “null”, info = “111”;

@Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);

    setContentView(R.layout.temperature);
    mHandler \= new Handler();

    BT\_find \= (TextView) findViewById(R.id.BT\_find);
    BT\_info \= (TextView) findViewById(R.id.BT\_info);
    BT\_link \= (TextView) findViewById(R.id.BT\_link);

          
Typeface typeface = Typeface.createFromAsset(getAssets(), “fonts/maozedong.ttf”);//设置显示字体
BT_find.setTypeface(typeface);
BT_info.setTypeface(typeface);
BT_link.setTypeface(typeface);

    BT\_find.setText("查找中");
    BT\_info.setText("null");
    BT\_link.setText("未连接"); if (!getPackageManager().hasSystemFeature(   //判断主机是否支BLE牙设备

PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, “BLE is not supported”, Toast.LENGTH_SHORT)
.show();
finish();

    } final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH\_SERVICE);//获得Android设备中的bluetoothmanager
    mBluetoothAdapter = bluetoothManager.getAdapter();//获得bluetoothadapter
    if (mBluetoothAdapter == null) {
        Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH\_SHORT)
                .show();
        finish(); return;
    }
    mBluetoothAdapter.enable(); //强制使能Bluetoothadapter,打开Android设备蓝牙
    mBLE = new BluetoothLeClass(this); //BLuetoothLeClass类
    if (!mBLE.initialize()) {
        Log.e(TAG, "Unable to initialize Bluetooth");
        finish();

    } // 发现BLE终端的Service时回调

mBLE.setOnServiceDiscoverListener(mOnServiceDiscover); // 收到BLE终端数据交互的事件
mBLE.setOnDataAvailableListener(mOnDataAvailable);

}

@Override protected void onResume() { // TODO Auto-generated method stub
    super.onResume();
    scanLeDevice(true);//搜索BLE设备

}

@Override protected void onPause() { // TODO Auto-generated method stub
    super.onPause();
    scanLeDevice(false);
    mBLE.disconnect();
}

@Override protected void onStop() { // TODO Auto-generated method stub
    super.onStop();
    mBLE.close();
} private void scanLeDevice(final boolean enable) { // TODO Auto-generated method stub
    if (enable) {

        mHandler.postDelayed(new Runnable() {

            @Override public void run() { // TODO Auto-generated method stub
                mScanning = false;
                mBluetoothAdapter.stopLeScan(mLeScanCallback);

            }
        }, SCAN\_PERIOD);//在搜索时间内,关闭搜索标志,不对搜索回调函数进行响应
        mScanning = true;
        mBluetoothAdapter.startLeScan(mLeScanCallback);

    } else {

        mScanning \= false;
        mBluetoothAdapter.stopLeScan(mLeScanCallback);

    }

} /\*\* \* 搜索到BLE终端服务的事件 \*/
private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener() {

    @Override public void onServiceDiscover(BluetoothGatt gatt) {

        displayGattServices(mBLE.getSupportedGattService());
    }

}; /\*\* \* 收到BLE终端数据交互的事件 \*/
private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener() { /\*\* \* BLE终端数据写入的事件 \*/ @Override public void onCharacteristicRead(BluetoothGatt gatt,
            BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT\_SUCCESS)
            Log.e(TAG, "onCharRead "
                            + gatt.getDevice().getName() \+ " read "
                            + characteristic.getUuid().toString() \+ " -> "
                            + Utils.bytesToHexString(characteristic
                                    .getValue()));

    } /\*\* \* 对BLE终端读取数据 \*/ @Override public void onCharacteristicWrite(BluetoothGatt gatt,
            BluetoothGattCharacteristic characteristic) {
        info \= new String(characteristic.getValue());//对得到的byte数组进行解码,构造新的string
        Log.e(TAG, "onCharWrite " + gatt.getDevice().getName() + " write "
                + characteristic.getUuid().toString() + " -> " + info); if (!S\_BT\_info.equals(info)) {//判断读取的数据是否发生变化,如果变化,更新UI
            DeviceScanActivity.this.runOnUiThread(new Runnable() {

                @Override public void run() { // TODO Auto-generated method stub
                    BT\_link.setText("已连接");
                    StringBuilder sb \= new StringBuilder();//详情参见:http://blog.csdn.net/rmn190/article/details/1492013

sb.append(info);
sb.append(“度”);
BT_info.setText(sb.toString());
sb = null;

                }
            });

        }

    }
}; private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {//搜索回调函数:
    String BT\_name = null;

    @Override public void onLeScan(final BluetoothDevice device, int rssi, byte\[\] scanRecord) { // TODO Auto-generated method stub
        runOnUiThread(new Runnable() {

            @Override public void run() { // TODO Auto-generated method stub
                BT\_name = device.getName(); if (BT\_name.equals(BTtoFind)) { //如果是要找的设备,更新UI上信息,设置搜索标志,停止响应搜索回调函数,连接BLE设备
                    /\*\* 连接事件 \*/ BT\_find.setText("已找到设备!");
                    mScanning \= false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    mBLE.connect(device.getAddress());

                }

            }
        });

    }
}; private void displayGattServices(BluetoothGattService bluetoothGattService) { if (bluetoothGattService == null) return; // -----Service的字段信息-----//
    int type = bluetoothGattService.getType();
    Log.e(TAG, "-->service type:" + Utils.getServiceType(type));
    Log.e(TAG, "-->includedServices size:"
            + bluetoothGattService.getIncludedServices().size());
    Log.e(TAG, "-->service uuid:" + bluetoothGattService.getUuid()); // -----Characteristics的字段信息-----//
    List<BluetoothGattCharacteristic> gattCharacteristics = bluetoothGattService
            .getCharacteristics(); for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
        Log.e(TAG, "---->char uuid:" + gattCharacteristic.getUuid()); int permission = gattCharacteristic.getPermissions();
        Log.e(TAG, "---->char permission:"
                        + Utils.getCharPermission(permission)); int property = gattCharacteristic.getProperties();
        Log.e(TAG, "---->char property:" + Utils.getCharPropertie(property)); byte\[\] data = gattCharacteristic.getValue(); if (data != null && data.length > 0) {
            Log.e(TAG, "---->char value:" + new String(data));
        } // UUID\_KEY\_DATA是可以跟蓝牙模块串口通信的Characteristic
        if (gattCharacteristic.getUuid().toString().equals(UUID\_KEY\_DATA)) { // 测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()
            mHandler.postDelayed(new Runnable() {
                @Override public void run() {
                    mBLE.readCharacteristic(gattCharacteristic);
                }
            }, 500); // 接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()
            mBLE.setCharacteristicNotification(gattCharacteristic, true); // 设置数据内容
            gattCharacteristic.setValue("send data->"); // 往蓝牙模块写入数据

mBLE.writeCharacteristic(gattCharacteristic);
} // —–Descriptors的字段信息—–//
List gattDescriptors = gattCharacteristic
.getDescriptors(); for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
Log.e(TAG, “——–>desc uuid:” + gattDescriptor.getUuid()); int descPermission = gattDescriptor.getPermissions();
Log.e(TAG, “——–>desc permission:”
+ Utils.getDescPermission(descPermission)); byte[] desData = gattDescriptor.getValue(); if (desData != null && desData.length > 0) {
Log.e(TAG, “——–>desc value:” + new String(desData));
}
}

    }

}

}

复制代码

复制代码

package com.TANK.temperature.BT; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; public class BluetoothLeClass{ private final static String TAG = BluetoothLeClass.class.getSimpleName(); private BluetoothManager mBluetoothManager; private BluetoothAdapter mBluetoothAdapter; private String mBluetoothDeviceAddress; private BluetoothGatt mBluetoothGatt; public interface OnConnectListener { public void onConnect(BluetoothGatt gatt);
} public interface OnDisconnectListener { public void onDisconnect(BluetoothGatt gatt);
} public interface OnServiceDiscoverListener { public void onServiceDiscover(BluetoothGatt gatt);
} public interface OnDataAvailableListener { public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status); public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic);
} private OnConnectListener mOnConnectListener; private OnDisconnectListener mOnDisconnectListener; private OnServiceDiscoverListener mOnServiceDiscoverListener; private OnDataAvailableListener mOnDataAvailableListener; private Context mContext; public void setOnConnectListener(OnConnectListener l){
mOnConnectListener = l;
} public void setOnDisconnectListener(OnDisconnectListener l){
mOnDisconnectListener = l;
} public void setOnServiceDiscoverListener(OnServiceDiscoverListener l){
mOnServiceDiscoverListener = l;
} public void setOnDataAvailableListener(OnDataAvailableListener l){
mOnDataAvailableListener = l;
} public BluetoothLeClass(Context c){
mContext = c;
} // Implements callback methods for GATT events that the app cares about. For example, // connection change and services discovered.
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { if(mOnConnectListener!=null)
mOnConnectListener.onConnect(gatt);
Log.i(TAG, “Connected to GATT server.”); // Attempts to discover services after successful connection.
Log.i(TAG, “Attempting to start service discovery:” + mBluetoothGatt.discoverServices());

        } else if (newState == BluetoothProfile.STATE\_DISCONNECTED) { if(mOnDisconnectListener!=null)
                mOnDisconnectListener.onDisconnect(gatt);
            Log.i(TAG, "Disconnected from GATT server.");
        }
    }

    @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT\_SUCCESS && mOnServiceDiscoverListener!=null) {
                mOnServiceDiscoverListener.onServiceDiscover(gatt);
        } else {
            Log.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override public void onCharacteristicRead(BluetoothGatt gatt,
                                     BluetoothGattCharacteristic characteristic, int status) { if (mOnDataAvailableListener!=null)
            mOnDataAvailableListener.onCharacteristicRead(gatt, characteristic, status);
    }

    @Override public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) { if (mOnDataAvailableListener!=null)
            mOnDataAvailableListener.onCharacteristicWrite(gatt, characteristic);
    }
}; /\*\* \* Initializes a reference to the local Bluetooth adapter.
 \*
 \* @return Return true if the initialization is successful. \*/
public boolean initialize() { // For API level 18 and above, get a reference to BluetoothAdapter through // BluetoothManager.
    if (mBluetoothManager == null) {
        mBluetoothManager \= (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH\_SERVICE); if (mBluetoothManager == null) {
            Log.e(TAG, "Unable to initialize BluetoothManager."); return false;
        }
    }

    mBluetoothAdapter \= mBluetoothManager.getAdapter(); if (mBluetoothAdapter == null) {
        Log.e(TAG, "Unable to obtain a BluetoothAdapter."); return false;
    } return true;
} /\*\* \* Connects to the GATT server hosted on the Bluetooth LE device.
 \*
 \* @param address The device address of the destination device.
 \*
 \* @return Return true if the connection is initiated successfully. The connection result
 \*         is reported asynchronously through the
 \*         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 \*         callback. \*/
public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) {
        Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false;
    } // Previously connected device.  Try to reconnect.
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && mBluetoothGatt != null) {
        Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (mBluetoothGatt.connect()) { return true;
        } else { return false;
        }
    } final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) {
        Log.w(TAG, "Device not found.  Unable to connect."); return false;
    } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false.
    mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
    Log.d(TAG, "Trying to create a new connection.");
    mBluetoothDeviceAddress \= address; return true;
} /\*\* \* Disconnects an existing connection or cancel a pending connection. The disconnection result
 \* is reported asynchronously through the
 \* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
 \* callback. \*/
public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized"); return;
    }
    mBluetoothGatt.disconnect();
} /\*\* \* After using a given BLE device, the app must call this method to ensure resources are
 \* released properly. \*/
public void close() { if (mBluetoothGatt == null) { return;
    }
    mBluetoothGatt.close();
    mBluetoothGatt \= null;
} /\*\* \* Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported
 \* asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)}
 \* callback.
 \*
 \* @param characteristic The characteristic to read from. \*/
public void readCharacteristic(BluetoothGattCharacteristic characteristic) { if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized"); return;
    }
    mBluetoothGatt.readCharacteristic(characteristic);
} /\*\* \* Enables or disables notification on a give characteristic.
 \*
 \* @param characteristic Characteristic to act on.
 \* @param enabled If true, enable notification.  False otherwise. \*/
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,//便于更新数据
                                          boolean enabled) { if (mBluetoothAdapter == null || mBluetoothGatt == null) {
        Log.w(TAG, "BluetoothAdapter not initialized"); return;
    }
    mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
} public void writeCharacteristic(BluetoothGattCharacteristic characteristic){
     mBluetoothGatt.writeCharacteristic(characteristic);
} /\*\* \* Retrieves a list of supported GATT services on the connected device. This should be
 \* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
 \*
 \* @return A {@code List} of supported services. \*/
public BluetoothGattService getSupportedGattService() {//根据service的UUID来获取service
    if (mBluetoothGatt == null) return null; return mBluetoothGatt.getService(UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb"));
}

}

复制代码

复制代码

public class Utils { private static HashMap<Integer, String> serviceTypes = new HashMap(); static { // Sample Services.
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_PRIMARY, “PRIMARY”);
serviceTypes.put(BluetoothGattService.SERVICE_TYPE_SECONDARY, “SECONDARY”);
} public static String getServiceType(int type){ return serviceTypes.get(type);
} //-——————————————
private static HashMap<Integer, String> charPermissions = new HashMap(); static {
charPermissions.put(0, “UNKNOW”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ, “READ”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED, “READ_ENCRYPTED”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM, “READ_ENCRYPTED_MITM”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE, “WRITE”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED, “WRITE_ENCRYPTED”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM, “WRITE_ENCRYPTED_MITM”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED, “WRITE_SIGNED”);
charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM, “WRITE_SIGNED_MITM”);
} public static String getCharPermission(int permission){ return getHashMapValue(charPermissions,permission);
} //-——————————————
private static HashMap<Integer, String> charProperties = new HashMap(); static {

    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_BROADCAST, "BROADCAST");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_EXTENDED\_PROPS, "EXTENDED\_PROPS");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_INDICATE, "INDICATE");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_NOTIFY, "NOTIFY");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_READ, "READ");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_SIGNED\_WRITE, "SIGNED\_WRITE");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_WRITE, "WRITE");
    charProperties.put(BluetoothGattCharacteristic.PROPERTY\_WRITE\_NO\_RESPONSE, "WRITE\_NO\_RESPONSE");
} public static String getCharPropertie(int property){ return getHashMapValue(charProperties,property);
} //\--------------------------------------------------------------------------
private static HashMap<Integer, String> descPermissions = new HashMap(); static {
    descPermissions.put(0, "UNKNOW");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_READ, "READ");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_READ\_ENCRYPTED, "READ\_ENCRYPTED");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_READ\_ENCRYPTED\_MITM, "READ\_ENCRYPTED\_MITM");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_WRITE, "WRITE");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_WRITE\_ENCRYPTED, "WRITE\_ENCRYPTED");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_WRITE\_ENCRYPTED\_MITM, "WRITE\_ENCRYPTED\_MITM");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_WRITE\_SIGNED, "WRITE\_SIGNED");
    descPermissions.put(BluetoothGattDescriptor.PERMISSION\_WRITE\_SIGNED\_MITM, "WRITE\_SIGNED\_MITM");
} public static String getDescPermission(int property){ return getHashMapValue(descPermissions,property);
} //这段代码没看明白,欢迎大神指教
private static String getHashMapValue(HashMap<Integer, String> hashMap,int number){
    String result \=hashMap.get(number); if(TextUtils.isEmpty(result)){
        List<Integer> numbers = getElement(number);
        result\=""; for(int i=0;i<numbers.size();i++){
            result+=hashMap.get(numbers.get(i))+"|";
        }
    } return result;
} /\*\* \* 位运算结果的反推函数10 -> 2 | 8; \*/
static private List<Integer> getElement(int number){
    List<Integer> result = new ArrayList<Integer>(); for (int i = 0; i < 32; i++){ int b = 1 << i; if ((number & b) > 0) 
            result.add(b);
    } return result;
} public static String bytesToHexString(byte\[\] src){  
    StringBuilder stringBuilder \= new StringBuilder(""); if (src == null || src.length <= 0) { return null;  
    } for (int i = 0; i < src.length; i++) { int v = src\[i\] & 0xFF;  
        String hv \= Integer.toHexString(v); if (hv.length() < 2) {  
            stringBuilder.append(0);  
        }  
        stringBuilder.append(hv);  
    } return stringBuilder.toString();  
}  

}

复制代码