话不多说直接进入正题
一、 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没有安装的问题
原因是 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<String, String> 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<String, String> 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<String> testList = ['时','分'],List<int> selectList, Function complateAction, Function deleteAction}) {
print('显示选择时间');
}
此时会报错,默认值必须为常量,修改代码
void showSelectTime(
{List<String> testList = const ['时','分'],List<int> 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<StudyAddPlanController>(tag: widget.planID);
planModel = Get.find<StudyAddPlanController>(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<StudyCircleDynamicDetailPage> {
}
若是对上文中的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<StudyCircleDynamicDetailPage> {
/// 动态ID
int feedID = 0;
/// 动态作者ID
int ugcUid = 0;
}
应把属性的赋值操作写在state内部,应为调用键盘前后state并没有重新生成,只是会重新调用build方法
2)键盘弹起的页面为StatelessWidget类型时, 已测试调用键盘弹起时同样会调用工厂方法和build方法。
具体这么设计或是为何flutter会这样设计,有待进一步探究,有知道的大佬,欢迎不吝赐教
九、Command PhaseScriptExecution failed with a nonzero exit code
achive时遇到这个报错,找个很多资料,试了各种办法,发现都没有效果,最后使用下边的方法搞定
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<UIApplicationLaunchOptionsKey,id> *)launchOptions {
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- 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代表是暗黑模式
十四 Pixel6 手机 开启手机手势操作后 若干页面 右滑抖动的问题
问题描述:Pixel6 手机 设置中开启手势操作, 此时右滑返回上个页面,此时大概率会出现页面抖动的问题
原因:我们的app若干页面有抖动的问题 若干页面没有,对比发现 这个抖动的影响因素 包括
1、页面是否添加了GestureDetector 外层添加了GestureDetector 不会抖动
2、个别布局 也不回抖动,具体的布局 没看出规律
3、手机关闭全屏手机 也没有该问题
解决:在页面的basePage中 添加GestureDetector,同时必须实现ontap方法,问题解决
十五 Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
E/flutter (20604): At this point the state of the widget's element tree is no longer stable.
E/flutter (20604): To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
原因是 我们在使用Context时,这个context已经不在element树中了 这个context是不安全的 使用到context的相应操作不会生效,控制台会打印如上报错新
// 我遇到的问题是调用如下代码 没有效果,查看代码发现调用该方法前,原context所在的视图会重绘,重绘导致context发生变化,进一步 导致原context为unsafe
showGeneralDialog<bool>(
context: context,
);
解决
1、对视图设置Key('key')或是不设置,这样会保证重绘时context不变
2、若是设置了ValueKey,每次刷新都会变化,这时若是使用了GetX,可以使用GetX.context
3.设置固定Key,使用时使用Key获取context
上述问题 只是可以解决问题 但是 原因没有研究,大概率是 手机的手势与flutter的手势兼容问题,之后升级flutter版本 看看是否好转