android低功耗蓝牙APP开发问题记录
16lz
2022-04-06
概述:实现了BLE扫描、连接、读写、通知接收等操作。
1、扫描方法的回调函数更改
在android5.0(SDK 21)以上时,BluetoothAdapter.startLeScan()和stopLEScan已经过时,所以在5.0以上时需要判定android版本.
扫描代码:
private void scanLeDevice(final boolean enable) { if (enable) { mHandler.postDelayed(new Runnable() { @Override public void run() { if (Build.VERSION.SDK_INT < 21) { mBluetoothAdapter.stopLeScan(mLeScanCallback); } else { mLEScanner.stopScan(mScanCallback); } } }, SCAN_PERIOD); if (Build.VERSION.SDK_INT < 21) { mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mLEScanner.startScan(filters, settings, mScanCallback); } } else { if (Build.VERSION.SDK_INT < 21) { mBluetoothAdapter.stopLeScan(mLeScanCallback); } else { mLEScanner.stopScan(mScanCallback); } } }
回调函数:
private ScanCallback mScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { Log.i("callbackType", String.valueOf(callbackType)); Log.i("result", result.toString()); BluetoothDevice btDevice = result.getDevice(); connectToDevice(btDevice); } @Override public void onBatchScanResults(List results) { for (ScanResult sr : results) { Log.i("ScanResult - Results", sr.toString()); } } @Override public void onScanFailed(int errorCode) { Log.e("Scan Failed", "Error Code: " + errorCode); } }; private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { Log.i("onLeScan", device.toString()); connectToDevice(device); } }); } };
2、Android6.0权限问题
在手机上编译调试时,由于android6.0系统APP权限改为手动添加,则在调试低版本android BLE程序时要在build.gradle中将targetSdkVersion改为23以下,否则会运行出错。要想完全解决该问题,则需要判断android系统版本,查看android6.0的权限文档对代码进行修改。
例如:
3、低功耗蓝牙读写通信
package com.example.lenovo.ss1003;import android.app.Service;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothGatt;import android.bluetooth.BluetoothGattCallback;import android.bluetooth.BluetoothGattCharacteristic;import android.bluetooth.BluetoothGattDescriptor;import android.bluetooth.BluetoothGattService;import android.bluetooth.BluetoothManager;import android.bluetooth.BluetoothProfile;import android.content.Context;import android.content.Intent;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.util.Log;import android.widget.Toast;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.UUID;import static android.bluetooth.BluetoothAdapter.STATE_DISCONNECTED;/** * Created by lenovo on 2016/11/8. */public class BluetoothLeService extends Service { //预定义 private Handler mHandler; private final String LIST_NAME = "NAME"; private final String LIST_UUID = "UUID"; private final static String TAG = BluetoothLeService.class.getSimpleName(); private ArrayList> mGattCharateristics = new ArrayList>();//蓝牙数据描述对象链表 private BluetoothManager bluetoothManager; private BluetoothAdapter bluetoothAdapter; private String mBluetoothDeviceAddress; private BluetoothGatt bluetoothGatt; public BluetoothGattService mBluetoothGattService; private BluetoothGattCharacteristic mBluetoothGattCharacteristic; private int mConnectionState = STATE_CONNECTED; private static final int STATE_CONNECTING = 1; private static final int STATE_CONNECTED = 2; static final String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; static final String ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; private static final String ACTION_GATT_SERVICES_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCONNECTED"; public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; public final static String ACTION_GATT_WRITE="com.example.bluetooth.le.ACTION_WRITE"; static final String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; static final String EXTRA_DATA = "com.example.bluetooth.le.EXTRA_DATA"; public final static UUID UUID_TENS_MEASUREMWNT = UUID.fromString(SampleGattAttributes.TENS_MEASUREMENT); public final static UUID UUID_TENS_CHARACTERISTIC = UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG); private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { //获取蓝牙的连接状态,gatt客户端,status蓝牙连接操作成功后的连接状态,newState返回新的连接状态 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { String intentAction; //判断蓝牙新的连接状态,更新并发送广播 if (newState == BluetoothProfile.STATE_CONNECTED) { intentAction = ACTION_GATT_CONNECTED; mConnectionState = STATE_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG, "Connected to GATT server"); Log.i(TAG, "Attempting to start service discovery" + bluetoothGatt.discoverServices()); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; Log.i(TAG, "Disconnected from GATT server"); broadcastUpdate(intentAction); } } //readCharacteristic的时候会触发 @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.e("---------------", "onCharacteristicRead可用"); } } //回调显示一个远程变化,broadcastUpdate更新变化数据; @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); Log.e("---------------", "onCharacteristicChanged可用"); } @Override public void onCharacteristicWrite(BluetoothGatt mBluetoothGatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(mBluetoothGatt, characteristic, status); Log.e(TAG, "onCharWrite " + mBluetoothGatt.getDevice().getName() + " write " + characteristic.getUuid().toString() + " -> "); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { Log.w("lwj", "lwj---onDescriptorRead"); // TODO Auto-generated method stub //super.onDescriptorRead(gatt, descriptor, status); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { UUID uuid = descriptor.getCharacteristic().getUuid(); } @Override public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { Log.w("lwj", "lwj---onReadRemoteRssi"); // TODO Auto-generated method stub super.onReadRemoteRssi(gatt, rssi, status); } @Override public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { Log.w("lwj", "lwj---onReliableWriteCompleted"); // TODO Auto-generated method stub super.onReliableWriteCompleted(gatt, status); }// 蓝牙连接后回调该函数,立即执行 onServicesDiscovered方法,下列Log都会在Android studio 的error中打印 @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { // TODO Auto-generated method stub super.onServicesDiscovered(gatt, status); //discoverServices()函数的回调函数 if (status == BluetoothGatt.GATT_SUCCESS) { Log.e(TAG, "discoverServices完成"); mBluetoothGattService = gatt.getService(UUID_TENS_MEASUREMWNT); //还需要进行判断是否为null if (mBluetoothGattService == null) { Log.e(TAG, "getService未成功"); } else { Log.e(TAG, "getService成功"); } //再通过mBluetoothGattService获得BluetoothGattCharacteri mBluetoothGattCharacteristic = mBluetoothGattService.getCharacteristic(UUID_TENS_CHARACTERISTIC); //还需要在进行判断是否为null if (mBluetoothGattCharacteristic == null) { Log.e(TAG, "getCharacteristic未成功"); } else { Log.e(TAG, "getCharacteristic成功"); } }else { Log.e(TAG, "discoverServices未完成");// Toast.makeText(MainActivity.this, "discover不成功,请再尝试", Toast.LENGTH_LONG).show(); } **Log.e("++++++++++++",displayGattServices(getSupportedGattServices()).get(3).get(7).toString()); //行为广播,可在已绑定的Acivity中获取; broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); }** }; //广播发送,更新意图对象。 private void broadcastUpdate(String action) { final Intent intent=new Intent(action); sendBroadcast(intent); } //更新蓝牙行为数据和远程设备 private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) { //创建意图对象 final Intent intent = new Intent(action); //如果TENS_MEASUREMWNT的UUID和获取设备UUID匹配; if (UUID_TENS_MEASUREMWNT.equals(characteristic.getUuid())) { int flag = characteristic.getProperties();//获取设备属性 int format = -1; if ((flag & 0x01) != 0) { format = BluetoothGattCharacteristic.FORMAT_UINT16;//将uuid转为16进制格式 Log.d(TAG, "Heart rate format UINT16"); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8;//将uuid转为8进制格式 Log.d(TAG, "Heart rate format UINT8"); } // final int TENS = characteristic.getIntValue(format, 1); Log.d(TAG, String.format("Recevied TENS data:%d", TENS)); intent.putExtra(EXTRA_DATA, String.valueOf(TENS));//将心率的数据添加到intent对象中; } else { //如果数据是byte形式数据,将遍历数据并转化为String形式添加到intent中; final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for (byte byteChar : data) { stringBuilder.append(String.format("%02X", byteChar)); intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString()); } } sendBroadcast(intent);//广播转发intent对象; } }//继承Binder类实现BluetoothLeService 的getService方法; public class LocalBinder extends Binder { BluetoothLeService getService() { return BluetoothLeService.this; } } private final IBinder mBinder = new LocalBinder(); //绑定intent对象,作为intent和service之间的数据传递中间者。 @Override public IBinder onBind(Intent intent) { return mBinder; } //解除绑定 @Override public boolean onUnbind(Intent intent) { close(); return super.onUnbind(intent); } public boolean initialize() { if (bluetoothManager == null) { bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);//通过蓝牙管理者获取当前系统蓝牙服务 if (bluetoothManager == null) { return false; } } bluetoothAdapter = bluetoothManager.getAdapter();//获取适配器 if (bluetoothAdapter == null) { return false; } return true; } /* * 获取低功耗蓝牙设备后,连接到GATT服务 * 目的设备的地址作为参数; * 连接初始化成功后异步连接到设备; * */ //判断蓝牙是否可连接 public boolean Connect(final String address) { if (bluetoothAdapter == null || address == null) { Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); return false; }else if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) && bluetoothGatt != null) { Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); if (bluetoothGatt.connect()) { mConnectionState = STATE_CONNECTING; return true; } else { return false; } } final BluetoothDevice device = bluetoothAdapter.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. bluetoothGatt = device.connectGatt(this,true, mGattCallback);//true是设置自动连接蓝牙; Log.e(TAG, "Trying to create a new connection."); if(bluetoothGatt.connect()){ // Toast.makeText(this, "连接成功",Toast.LENGTH_LONG).show(); //连接成功后,再进行discoverServices() //并在其回调函数中执行getService(),获得BluetoothGattService if(bluetoothGatt.discoverServices()){ Log.e(TAG, "discoverServices已经开始了"); }else{ Log.e(TAG, "discoverServices没有开始"); } } else{ Toast.makeText(this, "未连接成功,请再尝试", Toast.LENGTH_LONG).show(); } mBluetoothDeviceAddress = address; mConnectionState = STATE_CONNECTING; return true; } public void DisConnect(){ if(bluetoothAdapter==null||bluetoothGatt==null){ return; } bluetoothGatt.disconnect(); } //关闭服务,释放Service绑定对象 private void close() { if(bluetoothGatt==null){ return; } bluetoothGatt.close(); bluetoothGatt=null; } //读取蓝牙设备特征,如果蓝牙适配器为空则返回空对象;否则读取蓝牙特征值 public void readCharacteristic(BluetoothGattCharacteristic characterristic){ if(bluetoothAdapter==null||bluetoothGatt==null){ Log.e("=============", "适配器或协议栈为空"); }else { bluetoothGatt.readCharacteristic(characterristic); Log.e("=============", "开始读取"); } } //写入指定的characteristic public void writeCharacteristic(BluetoothGattCharacteristic characteristic) { if (bluetoothAdapter == null || bluetoothGatt == null) { Log.w(TAG, "BluetoothAdapter not initialized"); return; } bluetoothGatt.writeCharacteristic(characteristic); } //获取蓝牙支持的服务 public List getSupportedGattServices(){ if(bluetoothGatt==null) { return null; }else return bluetoothGatt.getServices(); } /* 设置蓝牙通信是否可获取通知; 如果bluetoothAdapter和bluetoothGatt都不为null,可向bluetoothGatt中设置蓝牙可通知; 其中public static String CLIENT_CHARACTERISTIC_READ="00002902-0000-1000-8000-00805f9b34fb",是notify中的descriptor的UUID,必须对其进行descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)设置,否知收不到通知。向设备写数据时需要延时操作(200m以上)才能在广播接收者内接收到notify。 */ public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled) { if (bluetoothAdapter == null || bluetoothGatt == null) { Log.e(TAG, "BluetoothAdapter not initalized"); return; }else { BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_READ)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); Log.e("设置descriptor:",descriptor.toString()); bluetoothGatt.setCharacteristicNotification(characteristic, enabled); Log.e("设置notify:",characteristic.getUuid().toString()+enabled); } } //遍历蓝牙service和Characteristic列表,返回二维数组; public ArrayList> displayGattServices(List gattServices) { if (gattServices == null){ return null;} String uuid = null; String unknownServiceString = getResources().getString(R.string.unknown_service); String unknownCharaString = getResources().getString(R.string.unknown_characteristic); ArrayList> gattServiceData = new ArrayList>(); ArrayList>> gattCharacteristicData = new ArrayList>>(); mGattCharateristics= new ArrayList>(); // Loops through available GATT Services. for (BluetoothGattService gattService : gattServices) { HashMap currentServiceData = new HashMap(); uuid = gattService.getUuid().toString(); currentServiceData.put( LIST_NAME, SampleGattAttributes.lookup(uuid, unknownServiceString)); currentServiceData.put(LIST_UUID, uuid); gattServiceData.add(currentServiceData); ArrayList> gattCharacteristicGroupData = new ArrayList>(); List gattCharacteristics = gattService.getCharacteristics(); ArrayList charas = new ArrayList(); // Loops through available Characteristics. for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { charas.add(gattCharacteristic); HashMap currentCharaData = new HashMap(); uuid = gattCharacteristic.getUuid().toString(); currentCharaData.put( LIST_NAME, SampleGattAttributes.lookup(uuid, unknownCharaString)); currentCharaData.put(LIST_UUID, uuid); gattCharacteristicGroupData.add(currentCharaData); //接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite() setCharacteristicNotification(gattCharacteristic, true); } mGattCharateristics.add(charas); gattCharacteristicData.add(gattCharacteristicGroupData); }/* Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(0).getUuid())); Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(1).getUuid())); Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(2).getUuid())); Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(3).getUuid())); Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(4).getUuid())); Log.e("---------", String.valueOf(mGattCharateristics.get(3).get(5).getUuid()));*/ return mGattCharateristics; } }
private BluetoothGattCharacteristic mGattCharateristics;//蓝牙数据描述对象链表 private BluetoothGatt mBluetoothGatt; private BluetoothLeService mBluetoothLeService; public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";//外部仪器地址 private String mDeviceAddress; BluetoothGattCharacteristic mCharacteristic; private ArrayList> mGattCharacteristics = new ArrayList>(); private final ServiceConnection mServiceConnection = new ServiceConnection() { **//初始化蓝牙连接服务,如果蓝牙初始化成功则进行蓝牙连接;如果没有此方法,广播接收者无法接收数据,则不能进行读写操作。** @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) iBinder).getService(); if (!mBluetoothLeService.initialize()) {//判断蓝牙是否初始化 finish(); } mBluetoothLeService.Connect(mDeviceAddress); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } }; private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { mGattCharacteristics=mBluetoothLeService.displayGattServices(mBluetoothLeService.getSupportedGattServices()); }else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { intent.getStringExtra(BluetoothLeService.EXTRA_DATA); Log.e("+++++++++++",intent.getStringExtra(BluetoothLeService.EXTRA_DATA).toString()); } } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_treatment); final Intent intent = getIntent(); mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS); Intent gattServiceIntent = new Intent(this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); }@Override protected void onResume() { super.onResume(); //发送数据,应该在按钮监听中添加,这里没有设置按钮,就添加在此方法中。 mGattCharateristics = mGattCharacteristics.get(3).get(8); Log.e("======",mGattCharateristics.getUuid().toString()); final int charaProp =mGattCharateristics.getProperties(); byte data[] = {(byte)0x33, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00}; //final int charaProp =CharacteristicService.getProperties(); if ((charaProp|BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) { if (mGattCharateristics != null) { Log.d("NotifyCharacteristic:", mGattCharateristics.toString()); mBluetoothLeService.setCharacteristicNotification( mGattCharateristics, true); } mGattCharateristics.setValue(data);//随便举个数据 mBluetoothLeService.writeCharacteristic(mGattCharateristics);//写命令到设备, Log.e("++++++","数据发送成功"); } } @Override protected void onPause() { super.onPause(); unregisterReceiver(mGattUpdateReceiver); } @Override protected void onDestroy() { super.onDestroy(); } private IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); return intentFilter; }
4、android全局变量设置
目的:用于获取的蓝牙BluetoothGattCharacteristic在activity之间传递,否则一个activity销毁后,另一个activity无法获取。
(1)、在AndroidManifest文件中配置全局变量。
<application android:allowBackup="true" android:name=".BluetoothGattBean" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> intent-filter> activity> application>
(2)、创建全局变量类
import android.app.Application;import android.bluetooth.BluetoothGattCharacteristic;import java.util.ArrayList;/** * Created by lenovo on 2016/12/20. */public class BluetoothGattBean extends Application { private ArrayList> bluetoothGattCharacteristicList; public void setBluetoothGattCharacteristicList(ArrayList> bluetoothGattCharacteristicList) { this.bluetoothGattCharacteristicList = bluetoothGattCharacteristicList; } public ArrayList> getBluetoothGattCharacteristicList() { return bluetoothGattCharacteristicList; }}
(3)、向全局变量中保存广播接收者获取的数据
btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { final BluetoothGattBean bluetoothGattBean= (BluetoothGattBean)getApplication(); bluetoothGattBean.setBluetoothGattCharacteristicList(mGattCharacteristics); Intent bleIntent = new Intent(DeviceControlActivity.this, BleCommunicationActivity.class); } });
(4)、获取上一个activity保存的全局变量数据用于读写操作。
btn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { value=0; intensity_value.setText("0"); final BluetoothGattBean bluetoothGattBean= (BluetoothGattBean)getApplication(); mGattCharacteristics=bluetoothGattBean.getBluetoothGattCharacteristicList(); mCharacteristic = mGattCharacteristics.get(3).get(8); Log.e("获取的BluetoothGattCharacteristic为:",mCharacteristic) });
5、倒计时
package utils;import android.content.Context;import android.util.AttributeSet;import android.widget.TextView;public class TimerTextView extends TextView implements Runnable { public static String Ltime = null; public TimerTextView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } private long mmin, msecond; private boolean run = false; public void setTimes(long[] times) { mmin = times[0]; msecond = times[1]; } private void ComputeTime() { msecond--; if (msecond < 0) { mmin--; msecond = 59; } } public boolean isRun() { return run; } public void beginRun() { this.run = true; run(); } public void stopRun() { this.run = false; }//多线程,时间按mm:ss格式显示 @Override public void run() { if (run) { ComputeTime(); if (mmin>9&&msecond>9) { String strTime = mmin + ":" + msecond; this.setText(strTime); }else if(mmin>9&&msecond<10){ String strTime = mmin + ":0"+ msecond; this.setText(strTime); }else if(mmin<10&&msecond>9) { String strTime = "0"+mmin + ":"+ msecond; this.setText(strTime); }else if(mmin<10&&msecond<10){ String strTime = "0"+mmin + ":0"+ msecond; this.setText(strTime); } postDelayed(this, 1000); } else { removeCallbacks(this); } if (mmin == 0 && msecond == 0) { stopRun(); } // Log.e("shijian:",getRemainTime()); }//回去剩余时间的分和秒 public long getRemainMinute() { return mmin; } public long getRemainSecond(){ return msecond; }}
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/bg" android:orientation="vertical"> <utils.TimerTextView android:id="@+id/treattime" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="30:00" android:gravity="center" android:textSize="52sp" android:textColor="#1987C9" /> LinearLayout>
6、不同分辨率手机界面适配
转载:http://blog.csdn.net/lmj623565791/article/details/46695347;
注:有Navigation bar的手机需要获取手机实际分辨率(减去navigation bar占用的尺寸)后再编写一套value布局。
更多相关文章
- 如何使用arm-eabi-gdb调试android c/c++程序
- Android(安卓)打开相机、相册获取图片文件,支持Android(安卓)9.0
- [置顶] 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解
- android 项目中规范使用SharedPreferences
- Android调用getSimSerialNumber获取iccid不完整
- Android中Intent介绍
- Android(安卓)uevent
- mybatisplus的坑 insert标签insert into select无参数问题的解决
- python起点网月票榜字体反爬案例