Flutter開發(fā)日常問題記錄

遞歸式讀取一定要做異常處理,否則遇到異常就會停止遞歸
  ///遞歸式讀取 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>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容