遞歸式讀取一定要做異常處理,否則遇到異常就會停止遞歸
///遞歸式讀取 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的架構(gòu)
Dart =>Skia【OpenGL】=>操作系統(tǒng)=>硬件
自定義UI的方式:
1.Widget組合其他組件
2.自繪CustomPainter、Canvas
3.自己實現(xiàn)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的使用,監(jiān)聽onNotification可以阻止冒泡
Notificaiton的dispatch方法,調(diào)用visitAncesterElements向上遍歷父級元素
-s指定設(shè)備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{
///先馬上調(diào)用一次
res = await asyncFunc();
if(res != null){
serialCodeStreamController.sink.add(res);
_factoryModeHandle(res, isFactoryMode);
}
}catch(e){
// 創(chuàng)建一個重復(fù)性定時器
Timer.periodic(Duration(milliseconds: 100), (timer) async {
// 增加計數(shù)【一定要先執(zhí)行,await asyncFunc() 可能永遠沒有返回,卡死當(dāng)前線程】
count++;
// 如果調(diào)用次數(shù)達到10次,取消定時器
if (count >= retryCount) {
timer.cancel();
showError(S.of(GlobalUtils.context).read_serial_code_error);
print('調(diào)用次數(shù)達到10次,取消定時器');
}
print('BlueToothLogic.recursiveTillSuccessFuncTimer.periodic');
// 調(diào)用blueToothLogic.setAmbientLight()
res = await asyncFunc();
if(res != null){
serialCodeStreamController.sink.add(res);
_factoryModeHandle(res!, isFactoryMode);
timer.cancel();
}
});
}
}
android/app/src/main/AndroidManifest.xml 配置藍牙權(quán)限和第三方登錄跳轉(zhuǎn)權(quán)限
<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>
<!-- 藍牙權(quán)限-->
<!-- 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>