递归式读取一定要做异常处理,否则遇到异常就会停止递归
///递归式读取 fffa电池电量
void recursiveReadFFFA()async{
Future.delayed(Duration(seconds: 1),()async{
List<int>? res;
///一定要try catch,否则一旦有异常,递归就会终止
try{
res = await observeCharacteristic?.read();
}catch(e){
print('BlueToothLogic.recursiveReadFFFA e:${e.toString()}');
}
if(res?[0] != null){
isCharging.value = res![0];
}
if(res?[2] != null){
batteryLevel.value = res![2];
}
int? highHex = res?[3];
int? lowHex = res?[4];
if(highHex != null && lowHex != null){
timeStarted.value = highHex* 255 + lowHex;
fffaList.value = res ?? [];
}
recursiveReadFFFA();
});
}
Flutter 打包 android端 apk 【终端生成签名文件上传Google Play】
https://juejin.cn/post/6944000831465193480
class _SignUpGuidePageState extends State<SignUpGuidePage> {
CrossFadeState crossFadeState = CrossFadeState.showFirst;
Timer? timer;
@override
void initState() {
// TODO: implement initState
super.initState();
timer = Timer.periodic(Duration(seconds: 2), (timer) {
if(mounted){
setState(() {
if (crossFadeState == CrossFadeState.showFirst) {
crossFadeState = CrossFadeState.showSecond;
} else {
crossFadeState = CrossFadeState.showFirst;
}
});
}
});
}
@override
void dispose() {
timer?.cancel();
super.dispose();
}
}
//断言的使用
assert(initialValue == null || controller == null),
不满足断言会抛异常
//Flutter的架构
Dart =>Skia【OpenGL】=>操作系统=>硬件
自定义UI的方式:
1.Widget组合其他组件
2.自绘CustomPainter、Canvas
3.自己实现RenderObject
ImageProvider的子类有NetworkImage和AssetImage
class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage
class AssetImage extends AssetBundleImageProvider
abstract class AssetBundleImageProvider extends ImageProvider<AssetBundleImageKey>
图片加载流程,load=>loadAsyn=>Resolve=>PutIfAbsent
ProxyWidget
class NotificationListener<T extends Notification> extends ProxyWidget
abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget
abstract class InheritedWidget extends ProxyWidget
NotificationListerner的使用,监听onNotification可以阻止冒泡
Notificaiton的dispatch方法,调用visitAncesterElements向上遍历父级元素
-s指定设备ADB
adb -s f40ecad7 /Users/jingkairen/Desktop/App/Lumaflex\ Mobile/build/app/outputs/apk/release/LumaFlex.apk
adb: failed to install /Users/jingkairen/Desktop/App/Lumaflex Mobile/build/app/outputs/apk/release/LumaFlex.apk: Failure [INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package com.nooancehelmet.lumaflex signatures do not match previously installed version; ignoring!]
adb -s f40ecad7 uninstall com.nooancehelmet.lumaflex
异常处理要考虑周全,asyncFunc可能抛异常,可能返回null,还有可能没返回
///轮询10次
Future<void> recursiveTillSuccessFunc(Future<List<int>?> Function() asyncFunc, {bool isFactoryMode = false,int retryCount = 10}) async{
List<int>? res;
int count = 0;
try{
///先马上调用一次
res = await asyncFunc();
if(res != null){
serialCodeStreamController.sink.add(res);
_factoryModeHandle(res, isFactoryMode);
}
}catch(e){
// 创建一个重复性定时器
Timer.periodic(Duration(milliseconds: 100), (timer) async {
// 增加计数【一定要先执行,await asyncFunc() 可能永远没有返回,卡死当前线程】
count++;
// 如果调用次数达到10次,取消定时器
if (count >= retryCount) {
timer.cancel();
showError(S.of(GlobalUtils.context).read_serial_code_error);
print('调用次数达到10次,取消定时器');
}
print('BlueToothLogic.recursiveTillSuccessFuncTimer.periodic');
// 调用blueToothLogic.setAmbientLight()
res = await asyncFunc();
if(res != null){
serialCodeStreamController.sink.add(res);
_factoryModeHandle(res!, isFactoryMode);
timer.cancel();
}
});
}
}
android/app/src/main/AndroidManifest.xml 配置蓝牙权限和第三方登录跳转权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kaiyan.energy_lounger_app">
<!-- Chrome谷歌浏览器-->
<queries>
<intent>
<action android:name=
"android.support.customtabs.action.CustomTabsService" />
</intent>
</queries>
<!-- 蓝牙权限-->
<!-- Tell Google Play Store that your app uses Bluetooth LE
Set android:required="true" if bluetooth is necessary -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
<!-- New Bluetooth permissions in Android 12
https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- legacy for Android 11 or lower -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- legacy for Android 9 or lower -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
<application
android:label="Energy Lounger"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- Chrome谷歌浏览器-->
<activity
android:name="com.amplifyframework.auth.cognito.activities.HostedUIRedirectActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="energy-lounger" />
<data android:scheme="energy-lounger-staging" />
</intent-filter>
</activity>
</application>
</manifest>