Flutter七日遊第六天:2018-12-21 天氣:雨-陰
對於問我怎麼學習的人,空口白牙說的是雞湯,我不喜歡喝也不喜歡作。java
文中根據實際狀況,分享一些我的的編程心得,本身參考一下,取長補短node
單線程
:Dart是單線程模型,單線程模型,單線程模型!!!什麼是單線程:
就是你是一我的在戰鬥
什麼是異步: 好比你要燒水(耗時操做),並不須要傻傻地等着水開才能去作下一件事(掃地)android
只要開火(方法調用),而後你就能夠去掃地(執行異步任務下面的方法),水燒開鳴叫(回調), 去沖水(處理異步任務結果)。git
Future至關於40米大砍刀,Stream至關於一捆40米大砍刀github
dart提供了關鍵字async(異步)
和await(延遲執行)
,至關於普通的便捷的小匕首spring
async
和await
的簡單使用感受網上一些教程上來就告訴你什麼樣是錯的,而後一步步糾正...最後都沒有完整代碼總結一下編程
我想最起碼應該先給個正確的示範吧...而後再說錯誤狀況json
//根據名稱讀取文件
readFile(name) {
//建立文件對象
var file = File(name);
return file.readAsString();
}
//讀取文件成功
readOk() async{
var result = await readFile(r"C:\Users\Administrator\Desktop\應龍.txt");
print(result);
}
main() {
readOk();
print("我是第幾?");
}
複製代碼
函數執行過程當中看到了
async
(燒水)會先去執行下面的操做(掃地),水燒開await
放行,print(result);
(沖水)canvas
async
和await
的分析也許你就問,不加async或await會怎麼樣?不一樣時加又會怎麼樣?windows
不加async或await
:就像日常代碼同樣順序執行
加async不加await
:然並卵
不加async加await
:報錯
Future
能夠看出:
file.readAsString()
返回的是:Future<String>
,
main() {
var file = File(r"C:\Users\Administrator\Desktop\應龍.txt");
Future<String> re = file.readAsString();
re.then((result) {
print(result);
});
print("我是第幾?");
}
複製代碼
這樣操做也能達到異步的效果,具體就不深刻說了
有時間打算寫一篇:基於Java
,Python
,JavaScript(ES6+)
,Dart
,node
(都是我曾涉及過的)
綜合討論一下單線程,多線程,同步,異步
,畢竟這幾個詞讓我挺煩心
構造函數
File(文件路徑)
File.fromUri(Uri資源路徑標識符)
File.fromRawPath(Uint8List rawPath)
複製代碼
Uri爲例
也許看到
File.fromUri(Uri uri)
你會說Uri我不會,而後就無論了,若是有空就看兩眼唄,又不會吃虧
個人經驗是先看它的構造方法,而後再看字段,再總覽一下方法名(Ctr+F12)
若是你對這個類一無所知,仍是先看粗略瞄一下文檔註釋,至少知道幹嗎的
通常都會有一句簡潔的話介紹它(英文不會,詞典查一下,讀原文檔:這道坎遲早要過的)
Android中對Uri有必定的認識,知道它是一個資源定位的標誌,就像門牌號吧。
---->[註釋第一句]------------
A parsed URI, such as a URL.
url咱們都知道:http://192.168.43.60:8089/file/springboot/data.json
-------------------------------------------------------------
它是由一下部分構成的:
http(協議名)://+ 192.168.43.60(域名) + :8089(端口) + file/springboot/data.json(資源地址)
好比我是資源,你要找我:
中國://安徽:合肥/瑤海區/XXX路/XXX小區/張風捷特烈
-------------------------------------------------------------
---->[Uri核心屬性]------------
factory Uri(
{String scheme,
String userInfo,
String host,
int port,
String path,
Iterable<String> pathSegments,
String query,
Map<String, dynamic /*String|Iterable<String>*/ > queryParameters,
String fragment})
複製代碼
var base = Uri.base;
print(base);//打印了跟路徑--file:///I:/Java/Android/FlutterUnit/toly/
----->[.parse方法測試]
static Uri parse(String uri, [int start = 0, int end])
//既然Uri.parse返回一個Uri對象,那麼它應該有Uri的相應屬性
var parse = Uri.parse("http://192.168.43.60:8089/file/springboot/data.json");
print("host=${parse.host}");//192.168.43.60
print("port=${parse.port}");//8089
print("path=${parse.path}");//file/springboot/data.json
print("query=${parse.query}");//
print("fragment=${parse.fragment}");//
----->[.http方法測試]
Uri.http(String authority, String unencodedPath,[Map<String, String> queryParameters])
----->[.http方法測試,它的註釋都寫成這樣了,你還不會用嗎?]-------
//Creates a new `http` URI from authority, path and query
//http://example.org/path?q=dart.
//new Uri.http("example.org", "/path", { "q" : "dart" });
複製代碼
學會分析bug
,不要輕易否認
首先保證網址是正確的
var file = File.fromUri(new Uri.http("192.168.43.60:8089", "/file/springboot/data.json"));
Unhandled exception:
Unsupported operation: Cannot extract a file path from a http URI
#0 _Uri.toFilePath (dart:core/uri.dart:2617:7)
#1 new File.fromUri (dart:io/file.dart:265:49)
#2 readFile (file:///I:/Java/Android/FlutterUnit/toly/test/base/8_io.dart:11:19)
複製代碼
也許你到走了,會想(固然我也是這樣):什麼鬼,老子看半天,TM不能用,浪費時間!
也許你會憤然而去,而我則會去分析錯誤的緣由(這就是面對錯誤的不一樣選擇)
前者可能永遠也不知道緣由,然後者即便最後無果,路上也會有所收穫(打字的如今,我還未去分析)
---->[bug的連接處:]
String toFilePath({bool windows}) {
if (scheme != "" && scheme != "file") {
throw new UnsupportedError(
"Cannot extract a file path from a $scheme URI");
}
// 原來是scheme的鍋------那scheme是什麼呢?
var uri = new Uri.http("192.168.43.60:8089", "/file/springboot/data.json");
print(uri.scheme);//http
//可見-- new Uri.http的scheme是http,而這裏不是file因此報錯
至少你的知識庫中多收錄了一條信息:File.fromUri()不能訪問非file類型的Uri
也知道了scheme大概是什麼東西,知識庫就是這樣一點一點本身累積的
---->[這麼重要的限制,方法上能不註明嗎?]-------
/**
* Create a File object from a URI.
*
* If [uri] cannot reference a file this throws [UnsupportedError].
若是uri未涉及 file會報錯: UnsupportedError
*/
factory File.fromUri(Uri uri) => new File(uri.toFilePath());
好吧,是一開始沒注意,到此一個錯誤就能夠畫上句號了
錯誤不可怕,可怕的是你不知道爲何而致使之後還會犯,總之踩的坑多了,就會知道坑在那裏
也許別人給說你那有坑,第一次當心的過去了,下一次沒人提醒你,你可能就掉下去
複製代碼
也許你不知道,文件拖到瀏覽器裏,也是能打開的,你所見的就是feil類型的Uri
//源碼上面還有不少註釋本身看....
* // file:///C:/xxx/yyy
* new Uri.file(r"C:\xxx\yyy", windows: true);
*/
factory Uri.file(String path, {bool windows})
複製代碼
而後你就會用File.fromUri了:
var file = File.fromUri(Uri.parse("file:///F:/SpringBootFiles/file/springboot/data.json"));
複製代碼
從一個小的API開始,讓本身儘量去多認識一些事物,並非說你要把源碼都理得很清楚
在本身接受範圍的150%以內能夠去嘗試,失敗了沒有關係,總比看那些駁來駁去的文章有意義
若是你想提升本身(這句話也是自勉):
不要讓本身總走在平坦的路上,有時登高望遠方能窺見美景,也不要一心只走險峯,當心失足。
今天心情不佳,廢話有點多,聽得進去的就聽,聽不進去的就無視,若是要駁我,請在評論區!!
Java裏文件夾也是File對象,Dart裏區分了出來
頗有意思,File和Directory的Api基本上都是同步,異步成對出現
默認recursive是false,只能建立下一級
main() {
var dir = Directory(r"C:\Users\Administrator\Desktop\dart\test\all\li");
dir.createSync(recursive: true);
}
複製代碼
main() async {
var dir = Directory(r"E:\Material\MyUI");
var list = dir.list();//默認非遞歸及只列出一級
list.forEach((fs){
print(fs.path);
});
}
複製代碼
main() async {
var dir = Directory(r"E:\Material\MyUI");
var list = dir.list(recursive: true);//遞歸列出全部文件
list.forEach((fs){
print(fs.path);
});
}
複製代碼
目錄下全部文件都列出來,就不貼圖了
看一下就好了
var dir = Directory(r"C:\Users\Administrator\Desktop\dart\test\all\li");
dir.rename(r"C:\Users\Administrator\Desktop\dart\test\all\hello");
複製代碼
//根據名稱讀取文件
readFile(name) async {
//建立文件對象
var file = File(name);
try {
//判斷是否存在
bool exists = await file.exists();
if (exists) {
//若是存在
print(await file.length()); //文件大小(字節)---137
print(await file.lastModified()); //最後修改時間---2018-12-21 13:49:35.000
print(file.parent.path); //獲取父文件夾的路徑---C:\Users\Administrator\Desktop\dart
return await file.readAsString(); //讀取文件並返回
} else {
await file.create(recursive: true); //不存在則建立文件
return "未發現文件,已爲您建立!Dart機器人:2333";
}
} catch (e) {
//異常處理
print(e);
}
}
複製代碼
另外還有幾種不一樣的打開方式,基本上Java都包含了,看名字也知道是什麼
和java同樣,默認全換:想要追加:參數加
mode: FileMode.append
main() async {
wirte(r"C:\Users\Administrator\Desktop\dart\應龍.txt");
}
wirte(name) async{
var file = File(name);
file.writeAsString("海的彼岸有我不曾見證的風采");
}
複製代碼
path_provider: ^0.4.1
:提供了三個路徑,勉強用用吧
localPath() async {
try {
print('臨時目錄: ' + (await getTemporaryDirectory()).path);
//----/data/user/0/com.toly1994.toly/cache
print('文檔目錄: ' + (await getApplicationDocumentsDirectory()).path);
//----/data/user/0/com.toly1994.toly/app_flutter
print('sd卡目錄: ' + (await getExternalStorageDirectory()).path);
//----/storage/emulated/0
} catch (err) {
print(err);
}
}
複製代碼
simple_permissions: ^0.1.9
:提供了動態權限申請
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
複製代碼
readFormSD() async {
try {
var perm =
SimplePermissions.requestPermission(Permission.ReadExternalStorage);
var sdPath = getExternalStorageDirectory();
sdPath.then((file) {
perm.then((v) async {
var res = await readFile(file.path + "/應龍.txt");
print(res);
});
});
} catch (err) {
print(err);
}
}
複製代碼
好了,這樣知識就對接完畢
比較基礎,就是讀取文件夾下的內容,設置給ListView的Item
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:simple_permissions/simple_permissions.dart';
class ListFilePage extends StatefulWidget {
@override
_ListFilePageState createState() => _ListFilePageState();
}
class _ListFilePageState extends State<ListFilePage>
with SingleTickerProviderStateMixin {
List<String> _files = [];
@override
void initState() {
super.initState();
localPath();
}
@override
Widget build(BuildContext context) {
//生成listView
var listview = ListView.builder(
itemCount: _files.length,
itemBuilder: (BuildContext context, int index) {
return Column(
children: <Widget>[
Container(
color: Colors.white,
padding: EdgeInsets.all(15),
child: renderItem(index))
],
);
},
);
return Scaffold(
appBar: AppBar(
title: Text("張風捷特烈"),
),
body: listview,
);
}
// 添加全部SD卡文件名稱
localPath() {
try {
var perm =
SimplePermissions.requestPermission(Permission.ReadExternalStorage);
var sdPath = getExternalStorageDirectory();
sdPath.then((file) {
perm.then((v) {
file.list().forEach((i) {
_files.add(i.path);
});
setState(() {});
});
});
} catch (err) {
print(err);
}
}
//渲染單條目
renderItem(index) {
return Row(
children: <Widget>[
Icon(
Icons.extension,
color: Colors.blue,
),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
_files[index],
style: TextStyle(fontSize: 18),
),
)),
Icon(Icons.arrow_forward),
Divider(height: 1)
],
);
}
}
複製代碼
在pubspec.yaml的dependencies下
http: ^0.11.3+17
複製代碼
個人服務器上提供了一些網絡請求的Api,若是你想本身搭建服務器接口,請看這篇
來回顧一下接口的api:
查詢接口:GET請求--------------------------------------------
----查詢全部:
http://www.toly1994.com:8089/api/android/note
----查詢偏移12條,查詢12條(即12條爲一頁的第2頁):
http://www.toly1994.com:8089/api/android/note/12/12
----按區域查詢(A爲Android數據,SB爲SpringBoot數據,Re爲React數據)
http://www.toly1994.com:8089/api/android/note/area/A
http://www.toly1994.com:8089/api/android/note/area/A/12/12
----按部分名稱查詢
http://www.toly1994.com:8089/api/android/note/name/材料
http://www.toly1994.com:8089/api/android/note/name/材料/2/2
----按類型名稱查詢(類型定義表見第一篇)
http://www.toly1994.com:8089/api/android/note/name/ABCS
http://www.toly1994.com:8089/api/android/note/name/ABCS/2/2
----按id名稱查
http://www.toly1994.com:8089/api/android/note/12
添改刪接口---------------------------------------------------------------
添-POST請求:http://www.toly1994.com:8089/api/android/note
更新-PUT請求:http://www.toly1994.com:8089/api/android/note/1
刪-DELETE請求:http://www.toly1994.com:8089/api/android/note/1
複製代碼
注:
client
你隨便取什麼名字都行,客戶端訪問服務端,因此我用client
import 'package:http/http.dart' as client;
main() {
getData((data) {
print(data);
});
}
getData(cbk) async {
var api = 'http://www.toly1994.com:8089/api/android/note/100';
try {
final response = await client.get(api);
if (response.statusCode == 200) {
cbk(response.body);
}
} catch (e) {
print(e);
}
}
複製代碼
若是你以爲回調有點low,也徹底能夠用Future(用什麼不是重點,怎麼簡潔怎麼來)
main() {
getData().then((data){
print(data);
});
}
Future<String> getData() async {
try {
final response = await client.get('http://www.toly1994.com:8089/api/android/note/100');
if (response.statusCode == 200) {
return response.body;
}
} catch (e) {
print(e);
}
}
複製代碼
main() {
add((data) {
print(data);
});
}
add(cbk) async {
var api = 'http://www.toly1994.com:8089/api/android/note';
var item = {
"type": "C",
"name": "插入測試",
"localPath": "null",
"jianshuUrl": "https://www.jianshu.com/p/12f8ab32591a",
"juejinUrl": "null",
"imgUrl":
"http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png",
"createTime": "2018-09-06",
"info": "null",
"area": "A"
};
try {
final response = await client.post(api, body: item);
if (response.statusCode == 200) {
cbk(response.body);
}
} catch (e) {
print(e);
}
}
複製代碼
main() {
set((data) {
print(data);
});
}
set(cbk) async {
var api = 'http://www.toly1994.com:8089/api/android/note/199';
var item = {
"type": "C",
"name": "修改測試",
"localPath": "null",
"jianshuUrl": "https://www.jianshu.com/p/12f8ab32591a",
"juejinUrl": "null",
"imgUrl":
"http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png",
"createTime": "2018-09-06",
"info": "null",
"area": "A"
};
try {
final response = await client.put(api, body: item);
if (response.statusCode == 200) {
cbk(response.body);
}
} catch (e) {
print(e);
}
}
複製代碼
main() {
delete((data) {
print(data);
});
}
delete(cbk) async {
var api = 'http://www.toly1994.com:8089/api/android/note/199';
try {
final response = await client.delete(api);
if (response.statusCode == 200) {
cbk(response.body);
}
} catch (e) {
print(e);
}
}
複製代碼
通常都是解析服務器端傳來的json,非後端基本不用生產json
{
"id": 100,
"type": "繪圖相關",
"name": "D5-Android繪圖之讓圖形動起來",
"localPath": "null",
"jianshuUrl": "https://www.jianshu.com/p/12f8ab32591a",
"juejinUrl": "null",
"imgUrl": "http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png",
"createTime": "2018-09-06",
"info": "之前在Html利用js控制SVG或canvas進行運動模擬。瀏覽器自帶window.requestAnimationFrame能不斷執行渲染在這...",
"area": "A"
}
複製代碼
class NoteBean {
int id;
String type;
String name;
String localPath;
String jianshuUrl;
String juejinUrl;
String imgUrl;
String createTime;
String info;
String area;
NoteBean.fromJson(Map<String, dynamic> map)
: id = map['id'],
name = map['name'],
localPath = map['localPath'],
jianshuUrl = map['jianshuUrl'],
juejinUrl = map['juejinUrl'],
imgUrl = map['imgUrl'],
createTime = map['createTime'],
info = map['info'],
area = map['area'];
}
複製代碼
var j =
'{"id":100,"type":"繪圖相關","name":"D5-Android繪圖之讓圖形動起來","localPath":"null","jianshuUrl":"https://www.jianshu.com/p/12f8ab32591a","juejinUrl":"null","imgUrl":"http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png","createTime":"2018-09-06","info":"之前在Html利用js控制SVG或canvas進行運動模擬。瀏覽器自帶window.requestAnimationFrame能不斷執行渲染在這...","area":"A"}';
var noteBean = NoteBean.fromJson(json.decode(j));
print(noteBean.name);//D5-Android繪圖之讓圖形動起來
複製代碼
{
"code": 200,
"msg": "操做成功",
"data": {
"id": 100,
"type": "繪圖相關",
"name": "D5-Android繪圖之讓圖形動起來",
"localPath": "null",
"jianshuUrl": "https://www.jianshu.com/p/12f8ab32591a",
"juejinUrl": "null",
"imgUrl": "http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png",
"createTime": "2018-09-06",
"info": "之前在Html利用js控制SVG或canvas進行運動模擬。瀏覽器自帶window.requestAnimationFrame能不斷執行渲染在這...",
"area": "A"
}
}
複製代碼
ResultBean
class ResultBean {
String msg;
int code;
NoteBean data;
ResultBean.fromJson(Map<String, dynamic> map)
: msg = map['msg'],
code = map['code'],
data = NoteBean.fromJson(map['data']);
}
複製代碼
var j =
'{"code":200,"msg":"操做成功","data":{"id":100,"type":"繪圖相關","name":"D5-Android繪圖之讓圖形動起來","localPath":"null","jianshuUrl":"https://www.jianshu.com/p/12f8ab32591a","juejinUrl":"null","imgUrl":"http://toly1994.com:8089/imgs/android/c3af376135a7abe0655c908195b271db.png","createTime":"2018-09-06","info":"之前在Html利用js控制SVG或canvas進行運動模擬。瀏覽器自帶window.requestAnimationFrame能不斷執行渲染在這...","area":"A"}}';
var result = ResultBean.fromJson(json.decode(j));
print(result.data.name);//D5-Android繪圖之讓圖形動起來
複製代碼
這裏data是一個json的數組,這樣訪問的服務端接口的數據處理就搞定了
{
"code": 200,
"msg": "操做成功",
"data": [
{
"id": 198,
"type": "繪圖相關",
"name": "",
"localPath": "---",
"jianshuUrl": "",
"juejinUrl": "---",
"imgUrl": "http://toly1994.com:8089/imgs/android/8a11d27d58f4c1fa4488cf39fdf68e76.png",
"createTime": "2021-02-18",
"info": "hh",
"area": "A"
},
{
"id": 200,
"type": "繪圖相關",
"name": "",
"localPath": "---",
"jianshuUrl": "",
"juejinUrl": "---",
"imgUrl": "http://toly1994.com:8089/imgs/android/8a11d27d58f4c1fa4488cf39fdf68e76.png",
"createTime": "2018-12-21",
"info": "hh",
"area": "A"
}
]
複製代碼
class ResultBean {
String msg;
int code;
var data;
ResultBean.fromJson(Map<String, dynamic> map)
: msg = map['msg'],
code = map['code'],
data = map['data'];
}
class NoteBean {
int id;
String type;
String name;
String localPath;
String jianshuUrl;
String juejinUrl;
String imgUrl;
String createTime;
String info;
String area;
NoteBean.fromJson(Map<String, dynamic> map)
: id = map['id'],
name = map['name'],
localPath = map['localPath'],
jianshuUrl = map['jianshuUrl'],
juejinUrl = map['juejinUrl'],
imgUrl = map['imgUrl'],
createTime = map['createTime'],
info = map['info'],
area = map['area'];
}
複製代碼
var j ='{"code":200,"msg":"操做成功","data":[{"id":198,"type":"繪圖相關","name":"","localPath":"---","jianshuUrl":"","juejinUrl":"---","imgUrl":"http://toly1994.com:8089/imgs/android/8a11d27d58f4c1fa4488cf39fdf68e76.png","createTime":"2021-02-18","info":"hh","area":"A"},{"id":200,"type":"繪圖相關","name":"","localPath":"---","jianshuUrl":"","juejinUrl":"---","imgUrl":"http://toly1994.com:8089/imgs/android/8a11d27d58f4c1fa4488cf39fdf68e76.png","createTime":"2018-12-21","info":"hh","area":"A"}]}';
var result = ResultBean.fromJson(json.decode(j));
print(NoteBean.fromJson(result.data[1]).imgUrl);//http://toly1994.com:8089/imgs/android/8a11d27d58f4c1fa4488cf39fdf68e76.png
複製代碼
好了,今天就到這裏,明天最後一天,敬請期待
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1-github | 2018-12-21 | Flutter第6天--異步-IO+網絡+json |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人掘金 | 我的網站 |
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持