Flitter 学习过程中遇到的那些坑(持续更新)

话不多说直接进入正题

一、 iOS真机运行加载网络图片报错 Failed host lookup: 'gimg2.baidu.com' (OS Error: nodename nor servname provided, or not known, errno = 8)

解决:初次看到这个问题首先想到的是iOS工程plist文件没有设置 NSAppTransportSecurity字段 果断加上,运行,发现依然饭太稀,换模拟器运行,很是完美,事情发展的有点离奇,别着急其实很简单
1、从手机删除工程,重启手机
2、flutter工程重启
3、iOS工程 clean一下
再次运行完美解决,就是这么简单,具体为何缓存这么顽固有待探究

二、flutter doctor提示plugin没有安装的问题
191616055028_.pic.jpg

原因是 Android Studio (4.1) 的插件位置换了, 而 flutter doctor 这个命令还是会去原来的位置查找这两个插件,

旧目录: ~/Library/Application\ Support/AndroidStudio4.1

新目录: ~/Library/Application\ Support/Google/AndroidStudio4.1/plugins

解决的办法是软链接一下 :
ln -s ~/Library/Application\ Support/Google/AndroidStudio4.1/plugins ~/Library/Application\ Support/AndroidStudio4.1

三、flutter网络请求框架的请求表单格式设置

开发过程中一般的网络请求表单格式包括三种
1.application/json json格式
2.application/x-www-form-urlencoded; charset=utf-8 form-urlencode
3.multipart/form-data; boundary=--dio-boundary-0223402156 form-data

下面分别介绍三种表单请求的不同设置

1.application/json

Map lastMap = {
      'name': '小明',
      'age': '12'
    };
_dio.post(urlPath, data: lastMap)

抓包发现 请求的content-type 为application/json

2.application/x-www-form-urlencoded; charset=utf-8

_dio.options.contentType = 'application/x-www-form-urlencoded; charset=utf-8';
response = await _dio.post(urlPath, data: lastMap);

3.multipart/form-data; boundary=--dio-boundary-0223402156

Map lastMap = {
      'name': '小明',
      'age': '12'
    };
FormData data = FormData.fromMap(lastMap);
response = await _dio.post(urlPath, data: data);
四、使用dio框架 mac使用Charles抓包问题

开发中使用charles抓包比较常见 dio内部做了处理需要自己设置一下

(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
        (HttpClient client) {
      client.findProxy = (url) {
        return 'PROXY yourIP:8888';
      };
 };
五、default value of optional parameter must be constant

先看下边的代码

void showSelectTime(
    {List testList = ['时','分'],List selectList, Function complateAction, Function deleteAction}) {
print('显示选择时间');
}

此时会报错,默认值必须为常量,修改代码

void showSelectTime(
    {List testList = const ['时','分'],List selectList, Function complateAction, Function deleteAction}) {
print('显示选择时间');
}

加了const,问题解决

六、使用get框架共享数据的问题,同一类型的controller数据会共享,页面销毁,数据不会释放

场景是这样的现在有个表单页,表单页提供新建个编辑的功能

StudyAddTaskController controller = Get.put(StudyAddTaskController());

编辑时对conreoller进行赋值,等新建表单的时候使用同样方法Get.put后获取到的数据竟是之前编辑的数据,

根据此种情况 需要设置相应数据的tag值,同时使用Get.find获取数据时,也需要传相应的tag值

// 注册
controller = Get.put(StudyAddPlanController(), tag: planID);

// 获取

planController = Get.find(tag: widget.planID);
planModel = Get.find(tag: widget.planID).planModel;

七、flutter_swiper 报错ScrollController not attached to any scroll views

使用flutter_swiper 若是需要对swiper的list个数做变动,在删除时会出现爆红,错误提示ScrollController not attached to any scroll views;开始单个list,添加一个后会出现swiper不可轮播,
针对以上问题只需对swiper添加key: UniqueKey即可

Swiper(
                          key: UniqueKey(),
                          controller: SwiperController(),
                          index: 0,
                          itemCount: swiperList.length,
                          containerHeight: 140,
                          itemWidth: Get.mediaQuery.size.width - 30,
                          scrollDirection: Axis.horizontal,
                          itemBuilder: (BuildContext context, int index) {
                            StudyFindTargetDetailModel model =
                                swiperList[index];
                            return swiperWidget(
                                index: index,
                                shouldAdd: () {
                                  return !(swiperList.length == 8);
                                },
                                model: model);
                          },
                          autoplay: false,
                          viewportFraction: 0.9,
                          autoplayDisableOnInteraction: true,
                          loop: true,
                          scale: 0.95,
)
八、关于键盘弹起需要注意的几个点

1、键盘弹起会自动顶起非滚动视图的底部视图,不需要监测键盘弹起设置底部视图的高度
2、若是不想底部非滚动视图随键盘弹起,可设置Scaffold的resizeToAvoidBottomInset属性为false
3、键盘弹起对widget的影响
1)键盘弹起的页面为StatefulWidget时,键盘弹起会重新调用widget的工厂方法,重新初始化,重新初始化后state的initState方法并不会调用,但是build方法会调用,由此短信state并没有重新生成,类似下边的写法

class StudyCircleDynamicDetailPage extends StatefulWidget {

/// 动态ID
  int feedID = 0;

  /// 动态作者ID
  int ugcUid = 0;
  StudyCircleDynamicDetailPage({Key key}) : super(key: key);

  StudyCircleDynamicDetailController controller =
      Get.put(StudyCircleDynamicDetailController());

  @override
  _StudyCircleDynamicDetailPageState createState() =>
      _StudyCircleDynamicDetailPageState();
}

class _StudyCircleDynamicDetailPageState
    extends State {
  

}

若是对上文中的feedID和ugcUid赋值后,调起键盘,这时候在工厂方法中并未对feeID和ugcUid进行赋值,导致两个属性的值变为初始值,此时再去调用其他用到这两个属性的方法就会出错,
同期调起键盘前后我们看一下detailPage的hashcode的值,前后也是不同的,所以调用键盘前后detailPage可认为是两个不同的对象正确的方式

class StudyCircleDynamicDetailPage extends StatefulWidget {
  StudyCircleDynamicDetailPage({Key key}) : super(key: key);

  StudyCircleDynamicDetailController controller =
      Get.put(StudyCircleDynamicDetailController());

  @override
  _StudyCircleDynamicDetailPageState createState() =>
      _StudyCircleDynamicDetailPageState();
}

class _StudyCircleDynamicDetailPageState
    extends State {
  /// 动态ID
  int feedID = 0;

  /// 动态作者ID
  int ugcUid = 0;
}

应把属性的赋值操作写在state内部,应为调用键盘前后state并没有重新生成,只是会重新调用build方法
2)键盘弹起的页面为StatelessWidget类型时, 已测试调用键盘弹起时同样会调用工厂方法和build方法。
具体这么设计或是为何flutter会这样设计,有待进一步探究,有知道的大佬,欢迎不吝赐教

九、Command PhaseScriptExecution failed with a nonzero exit code

achive时遇到这个报错,找个很多资料,试了各种办法,发现都没有效果,最后使用下边的方法搞定

截屏2021-09-08 上午1.07.17.png

flutter中经常会出现各种打不了包\运行不了模拟器的情况,其中很多都和缓存有关,根据个人的经验,可以进行以下操作(前5步不分先后):

执行flutter clean
运行Xcode->Product->Clean
删除ios/.symlinks文件夹
删除ios/Pods文件夹
删除ios/Podfile.lock
在ios文件夹下执行pod install
重新打包/编译

这一系列操作能解决很多因为缓存导致的问题,如果你的flutter项目突然出了奇奇怪怪的问题不能打包,先试一下这些操作,可解决大部分的问题

如果以上方法没有效果,比如我就遇到了这个问题,各种清理就是没有效果,这个时候不要着急,使用android studio跑一下项目,找一个可以跑起来的日期,重新清理,发现竟然可以了,是不是很神奇,猜测是studio清理了缓存或是修复了某些东西

十、FlutterPlugin接受iOS的Appdelegate的相关回调&AppDekegate添加相关代理方法后对plugin的影响及解决方法

先说一下探究这个问题的缘由:使用QQ或是微信分享,拿到分享结果的回调,但是app中添加了通用链接打开app进入相应的详情的功能之后,发现QQ或是微信不能拿到分享结果的回调了,肯定是appdelegate添加userActivity方法后导致plugin中的方法没有调用,才有了以下的探究

1、若是我们的plugin想拦截或是获取appdelegate的相关回调可使用类似如下方法,instance 就拥有了获取回调的能力

FluwxPlugin *instance = [[FluwxPlugin alloc] initWithRegistrar:registrar methodChannel:channel];
[registrar addMethodCallDelegate:instance channel:channel];
[[FluwxResponseHandler defaultManager] setMethodChannel:channel];
[registrar addApplicationDelegate:instance];

2、使plugin中和appdelegate中都能获取回调方法
1)appdelegate继承自FlutterAppDelegate时,只需在相应的代理方法中调用super的相关方法,问题即解决;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
    [super application:application didFinishLaunchingWithOptions:launchOptions];
    
    return YES;
}
  1. appdelegate没有继承自FlutterAppDelegate
    参考官网这里说的很清楚
十一 使用VSCode打包 报错 R8: java.lang.OutOfMemoryError: GC overhead limit exceeded

查阅资料大概意思是堆内存溢出了

解决 找到安卓工程-Project-gradle.properties找到org.gradle.jvmargs=-Xmx1536m,将值改大一些
具体原因看这里

十二 使用TabBarView 加载两个不同的page时,切换page上一个page会重新调用initState和dispone方法

问题: 使用TabBarView加载page1和page2,当切换到page2时,会调用page1的dispone方法,重新切回page1会调用initState方法, 这样会导致我使用的EventBus的同步机制失效

探究: TabBarView在切换的时候,会重新的刷新当前页面,内部机制导致

解决: 给page1添加混入AutomaticKeepAliveClientMixin 类,并重写bool wantKeepAlive = true;即让当前page保持状态,告知不需要重新绘制,问题解决

十三 适配暗黑模式,获取手机系统的主题模式

导入 import 'dart:ui';

我们使用GetX管理路由及主题模式
改变

Get.changeThemeMode(index == 0
        ? ThemeMode.system
        : index == 1
            ? ThemeMode.light
            : ThemeMode.dark);

获取模式

Get.isDarkModel

问题是调用了改变方法,设置为跟随系统后,获取到的主题模式与系统不匹配,说明不是立刻生效
如下方法可获取系统模式
获取 window.platformBrightness 的值 如果是 Brightness.light 代表是正常模式, 如果是Brightness.dark代表是暗黑模式

你可能感兴趣的:(Flitter 学习过程中遇到的那些坑(持续更新))