Flutter|Flutter 问题收集及解决方案 持续更新中...
前端小弟一个,Flutter初学者,问题都是项目中遇到的,所以记录了下来。
前端个人博客.
目前尝试用Flutter还原豆瓣 ,以此来深入了解Flutter,求大佬们给个Star ? ?
https://github.com/jahnli/flutter_jahn_douban
【Flutter|Flutter 问题收集及解决方案 持续更新中...】解决方案来自于日常总结及各路大佬。
1. Waiting for another flutter command to release the startup lock…
```javascript
打开新的项目或者使用Flutter Packages get时出现: Waiting for another flutter command to release the startup lock...
解决方案:
先打开任务管理器,结束掉所有dart.exe即可,如果依然提示就打开你的flutter安装文件夹,找到\bin\cache中的lockfile文件删除。
之后重启项目。
```
2. The Gradle failure may have been because of AndroidX incompatibilities in this Flutter app
Android dependency 'androidx.core:core' has different version for the compile (1.0.0) and runtime (1.0.1) classpath. You should manually set the same version via DependencyResolution解决方案一:设法通过添加这样的代码片段来修复错误
在项目 android > build.gradle 文件中buildscript { }中添加此代码片段
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.android.support'
&& !details.requested.name.contains('multidex') ) {
details.useVersion "27.1.1"
}
if (details.requested.group == 'androidx.core'
&& !details.requested.name.contains('androidx') ) {
details.useVersion "1.0.1"
}
}
}
}解决方案二:1.android/gradle/wrapper/gradle-wrapper.properties里面
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip2.android/build.gradle
dependencies { classpath 'com.android.tools.build:gradle:3.3.0' }3.android/gradle.properties
加入
android.enableJetifier=true
android.useAndroidX=true4.android/app/build.gradle 修改版本号:
make sure compileSdkVersion and targetSdkVersion are at least 28.
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"5.android/app/build.gradle /defaultConfig加上
multiDexEnabled true
3. Error connecting to the service protocol: HttpException: Connection closed before full header was…
```javascript最后是使用安卓系统版本是9.1 Android版本太高,换8.1就好了查看 Android Studio Sdk Manager 版本 查看项目App目录下 compileSdkVersion```
4. type ‘List’ is not a subtype of type ‘List’
```javascript这里的问题是类型推断以意想不到的方式失败。解决方案是为map方法提供类型参数
Wrap(
children:item['casts'].map((casts){
return Text('data');
}).toList(),
)更复杂的答案是,虽然类型children是List,该信息不会回流到map调用。这可能是因为map后面是toList因为没有办法输入注释闭包的返回。```
5. chewie插件在ios下播放失败的问题
```javascriptNSAppTransportSecurity
NSAllowsArbitraryLoads
```
6. snackBar报错的问题无法弹出,Scaffold.of() called with a context that does not contain a Scaffold.
```javascript
// 定义一个GlobarKey
GlobalKey _scaffoldKey = GlobalKey();
//
return new Scaffold(
key: _scaffoldkey,
........
),
.......
)// 通过key调用snackbar
onPressed: (){
_scaffoldKey.currentState.showSnackBar(
SnackBar(
content: Text("这是一个SnackBar"),
duration: Duration(
milliseconds: 1
),
action: SnackBarAction(
label: "别点我",
onPressed: () {
print("SnackBar上面的按钮被点击了");
}
),
)
);
},
)```
7. 脚手架sliver、scaffold中设置appbar、tabbar的高度或者背景色
```javascript// 尤其是AppBar和TabBar,如果不希望被限制size,需要提供preferredSize或默认值
// 想要设置高度或者背景色,在AppBar外包一层PreferredSize,设置preferredSize的属性为想要的高度即可。
SliverPersistentHeader(
pinned: true,
delegate: StickyTabBarDelegate(
child:PreferredSize(
preferredSize: Size.fromHeight(40),
child: Material(
color: Colors.grey[200],
child: TabBar(
labelColor: Colors.black,
controller: this._tabController,
indicatorColor: Colors.black,
tabs: [
Tab(text: '评论'),
Tab(text: '话题区'),
],
),
),
),
),
),```
8. 去掉状态栏代码实现
```javascript做Flutter做屏效果显示的时候,调用SystemChrome.setEnabledSystemUIOverlays([]);
这个方法把状态栏和虚拟按键隐藏掉跳转到其他页面后需要调用把状态栏显示出来,调用SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]);
需要一起调用底部虚拟按键(华为系列某些手机有虚拟按键),则SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top, SystemUiOverlay.bottom]);
```
9. Image.File 加载图像时文件内容变化但图像不变
```javascript在Flutter中,我们可以用下面的代码从文件中加载图像:Image.file(File(_fileName));
这个时候,当_fileName这个文件名称和路径不变,文件内容变化时,Flutter并不会更新显示。问题产生的原因是Flutter自动使用了缓存。Image.file 实际上会将 image 设置为 FileImage 这个 ImageProvider。FileImage 的代码中,在进行 operator 时,只判断了文件路径和缩放比例。正是因为如此,我们文件路径不变,缩放比例不变时,Flutter会认为我们还是用的原图,并不会重新进行加载。于是,我想到了办法是扩展一个FileImage,将这个 operator 的方式改一下。新创建一个类class FileImageEx extends FileImage {
int fileSize;
FileImageEx(File file, { double scale = 1.0 })
: assert(file != null),
assert(scale != null),
super(file, scale: scale) {
fileSize = file.lengthSync();
}@override
bool operator ==(dynamic other) {
if (other.runtimeType != runtimeType)
return false;
final FileImageEx typedOther = other;
return file?.path == typedOther.file?.path
&& scale == typedOther.scale && fileSize == typedOther.fileSize;
}}接下来,直接使用下面的代码来加载图像:Image(image: FileImageEx(File(_fileName)));
```
10. Inkell 去掉水波纹的方法
```javascript// 设置highlightColor为透明,同时设置radius为0
InkWell(
highlightColor:Colors.transparent,
radius: 0.0,
onTap: (){
},
child: Text('跳过 ${_time}s'),
),```
11. 打包release版本安卓apk包真机无法请求网络
```javascript
// 原因:安卓开发中flutter应用没有网络权限在项目目录android\app\src\profile\AndroidManifest.xmlmanifest 里添加这段代码
在项目目录 android/src/main/AndroidManifest.xml 里也有一个 AndroidManifest.xml文件!跟之前的只不过是文件夹位置不同而已,同样在manifest标签下加入相同配置就行了,不要放到application里
重新打包即可```
12. setstate() called after dispose() ,setstate导致的内存泄漏
```javascript// flutter端请求网络时,调用的是宿主App的网络请求。
// flutter通过消息通道发送一个消息,然后await等待消息返回,最终宿主app会调用reply.reply(obj)方法返回数据。
// 如果在这个过程中,flutter页面关闭,就会出现如下异常,类似Android中的内存泄漏。/* setState() called after dispose(): _DetailCommentsState#5c3a1(lifecycle state: defunct, not mounted)
I/flutter ( 4677): This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
I/flutter ( 4677): The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
I/flutter ( 4677): This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object
after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose(). */// 我们的错误原因是异步消息未返回,所以在setState方法之前调用mouted属性进行判断即可。具体示例如下:if(mounted){
setState(() {
_movie = res.data;
_themeColor = paletteGenerator.colors.toList()[1];
_detailThemeColor = paletteGenerator.colors.toList()[0];
});
}```
13. xcode打包时提示Could not find included file ‘Generated.xcconfig’ in search paths (in target ‘Runner’)
```javascript// 尝试执行flutter build ios然后重新启动Xcode```
14. 更新showDialog以及showModalBottomSheet中的状态中的内容
```javascript
// 很多人在用showDialog的时候应该都遇到过这个问题,使用showDialog后,通过setState()无法更新当前dialog。其实原因很简单,因为dialog其实是另一个页面,准确地来说是另一个路由,因为dialog的关闭也是通过navigator来pop的,所以它的地位跟你当前主页面一样。这个概念一定要明确,因为无论在Android或iOS中,daliog都是依附于当前主页面的一个控件,但是在Flutter中不同,它是一个新的路由。所以使用当前主页面的setState()来更新,当然没法达到你要的效果。/* StatefulBuilder
很多人使用StatefulBuilder依然达不到更新的效果,是因为你用错了setState()方法。
就像我们上面说的那样,这个builder构建的控件,不会响应老页面的任何操作,因为它们是两个互不影响的路由控制的。 */// 1、更新showDialog
showDialog(
context: context,
builder: (context) {
String label = 'test';
return StatefulBuilder(
builder: (context, state) {
print('label = $label');
return GestureDetector(
child: Text(label),
onTap: () {
label = 'test8';
print('onTap:label = $label');
// 注意不是调用老页面的setState,而是要调用builder中的setState。
//在这里为了区分,在构建builder的时候将setState方法命名为了state。
state(() {});
},
);
},
);
}
);
// 2、更新showModalBottomSheet
showModalBottomSheet(context:context, builder:(BuildContext context){
return StatefulBuilder(
builder:(context1, state) {///这里的state就是setState
return Container(
child:OutlineButton(
onPressed: (){
state(() {///为了区分把setState改个名字
btnState=!btnState;
});
},
child:Stack(
children: [
Opacity(
opacity: btnState ? 0.0 : 1.0,
child: Text("aa"),
),
Opacity(
opacity: btnState ? 1.0 : 0.0,
child: Text("bb"),
)
],
),
),
),
}
)
})
```
15. SliverPersistentHeader 组件内状态更新,但UI未更新
```javascriptSliverPersistentHeader(
pinned: true,
delegate: SliverBarDelegate(
PreferredSize(
preferredSize: Size.fromHeight(ScreenAdapter.height(80)),
child:_headActions()
),
),
),// SliverPersistentHeaderdelegate的是重写的SliverBarDelegate
class SliverBarDelegate extends SliverPersistentHeaderDelegate {
finalwidget;
SliverBarDelegate(this.widget);
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
child: widget,
);
}
// 是否需要重新构建
// 如果传递的这几个参数变化了,那就重写创建
// 如果返回false,则可能不会重新构建报头,即使委托的实例发生了变化。
// 源代码中有描述到@override
bool shouldRebuild(SliverBarDelegate oldDelegate) {
return true;
}@override
double get maxExtent => widget.preferredSize.height;
@override
double get minExtent => widget.preferredSize.height;
}```
16. packages get 慢的解决方案
```javascript /*
国内使用 flutter packages get 命令,一直是This is taking an unexpectedly long time 状态科学上网无效windows解决方案:配置 【环境变量】 > 【用户变量】:变量名:PUB_HOSTED_URL值:https://pub.flutter-io.cn变量名:FLUTTER_STORAGE_BASE_URL值:https://storage.flutter-io.cn最好重启下windows电脑,flutter packages get 执行*/![Alt](http://cdn.jahnli.cn/2019031011234522.png)
![Alt](http://cdn.jahnli.cn/20190310112504126.png)// 具体环境变量的值 需要看该网址 [Using Flutter in China: ](https://flutter.dev/community/china). ```
推荐阅读
- parallels|parallels desktop 解决网络初始化失败问题
- jhipster|jhipster 升级无效问题
- “精神病患者”的角度问题
- 解决SpringBoot引用别的模块无法注入的问题
- Hive常见问题汇总
- 姚老师互动问答会|姚老师互动问答会 # 问题001(如何更有智慧的和身边人分享金刚智慧())
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- 【教育故事】|【教育故事】 一个“问题学生”的蜕变
- 蓝桥杯试题
- 记录iOS生成分享图片的一些问题,根据UIView生成固定尺寸的分享图片