Flutter:如何将用户创建的对象存储在本地存储中并将它们检索到 ListView 中
Flutter: How can I store user created objects in local storage and retrieve them into a ListView
我正在 Flutter 中重新创建我的应用程序 Call Manager,但我很难存储对象并将它们检索到列表中。使用 SharedPreferences 和 GSON 适用于完整的 Android 应用程序,但由于 GSON 在 Flutter 中不存在,在我看来,将 onjects 存储为 JSON 数据是可行的方法。
流程应该是这样的:
用户在 AddNewCall 屏幕上添加一个新呼叫。这包括姓名、phone 号码和可选说明'
当用户单击 'Save' 按钮时,将根据这些字段中的文本创建一个 Call 对象。该对象被编码成这样的字符串:String jsonData = json.encode(newCallObject);
使用 getApplicationDocumentsDirectory()
将通话 JSON 数据保存到应用程序的本地存储中
用户被带回主屏幕,其中 JSON 文件将在 initState()
方法中异步加载到应用程序中。
JSON 数据被解码并添加到 ListView
我遇到的问题是,当 JSON 数据添加到文件是第 3 步时,它看起来像这样:{sampleData}{sampleData}
而不是作为数组被包围在 []
中。因此,应用程序在读取文件时出现问题。到目前为止,我的解决方案是将文件的内容解析为一个数组,在 }{ 之间添加一个下划线,并将结果字符串拆分为一个字符串类型的数组。它看起来像这样:
String jsonCalls = await file.readAsString();
jsonCalls = jsonCalls.replaceAll('}{', '}_{');
List<String> temp = jsonCalls.split('_');
所以现在我得到了一个包含 JSON 字符串的数组,但我仍然无法访问每个 JSON 字符串中的值。我采用的整个方法似乎也过于复杂了。一定有更好的方法,但我疯狂地用谷歌搜索却一无所获。你们能帮帮我吗?
谢谢!
这里有一些建议
- Flutter 支持使用 plugin 的共享首选项,因此它应该与 Android 相似。
initState
仅在第一次初始化 StatefulWidget 时调用,因此可能不是期望重新加载更改信息的好地方
- 考虑将您的工作状态保存在内存中,例如在
List<Call>
中,您可以轻松地向其中添加新调用。
- 当您将此
List
序列化为 json 时,它将按预期包含在括号中。写入整个列表,覆盖之前的版本。
- 使用后备存储(文件或共享首选项)作为应用程序使用之间的持久性,因此在启动时读取一次,并在每次修改时将其写入内存中。内存中的副本是主副本,而应用程序是 运行.
这应该可以减少将 json 破解为字符串的需要。
可能是这样的:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Call Manager',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Call> calls = [];
@override
void initState() {
super.initState();
load();
}
load() async {
// initially populate calls by getting last value from shared preferences and parsing it
}
persist() async {
// encode calls as json and write to share prefs
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Calls'),
),
body: new ListView(
scrollDirection: Axis.horizontal,
children: calls
.map((call) => new ListTile(
title: new Text(call.phoneNumber),
))
.toList(),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.push<Call>(
context,
new MaterialPageRoute(
builder: (context) => new SecondPage(),
),
).then((newCall) {
if (newCall != null) {
setState(() {
calls.add(newCall);
});
persist();
}
});
},
tooltip: 'New',
child: new Icon(Icons.add),
),
);
}
}
我正在 Flutter 中重新创建我的应用程序 Call Manager,但我很难存储对象并将它们检索到列表中。使用 SharedPreferences 和 GSON 适用于完整的 Android 应用程序,但由于 GSON 在 Flutter 中不存在,在我看来,将 onjects 存储为 JSON 数据是可行的方法。
流程应该是这样的:
用户在 AddNewCall 屏幕上添加一个新呼叫。这包括姓名、phone 号码和可选说明'
当用户单击 'Save' 按钮时,将根据这些字段中的文本创建一个 Call 对象。该对象被编码成这样的字符串:String jsonData = json.encode(newCallObject);
使用 getApplicationDocumentsDirectory()
将通话 JSON 数据保存到应用程序的本地存储中
用户被带回主屏幕,其中 JSON 文件将在 initState()
方法中异步加载到应用程序中。
JSON 数据被解码并添加到 ListView
我遇到的问题是,当 JSON 数据添加到文件是第 3 步时,它看起来像这样:{sampleData}{sampleData}
而不是作为数组被包围在 []
中。因此,应用程序在读取文件时出现问题。到目前为止,我的解决方案是将文件的内容解析为一个数组,在 }{ 之间添加一个下划线,并将结果字符串拆分为一个字符串类型的数组。它看起来像这样:
String jsonCalls = await file.readAsString();
jsonCalls = jsonCalls.replaceAll('}{', '}_{');
List<String> temp = jsonCalls.split('_');
所以现在我得到了一个包含 JSON 字符串的数组,但我仍然无法访问每个 JSON 字符串中的值。我采用的整个方法似乎也过于复杂了。一定有更好的方法,但我疯狂地用谷歌搜索却一无所获。你们能帮帮我吗?
谢谢!
这里有一些建议
- Flutter 支持使用 plugin 的共享首选项,因此它应该与 Android 相似。
initState
仅在第一次初始化 StatefulWidget 时调用,因此可能不是期望重新加载更改信息的好地方- 考虑将您的工作状态保存在内存中,例如在
List<Call>
中,您可以轻松地向其中添加新调用。 - 当您将此
List
序列化为 json 时,它将按预期包含在括号中。写入整个列表,覆盖之前的版本。 - 使用后备存储(文件或共享首选项)作为应用程序使用之间的持久性,因此在启动时读取一次,并在每次修改时将其写入内存中。内存中的副本是主副本,而应用程序是 运行.
这应该可以减少将 json 破解为字符串的需要。
可能是这样的:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Call Manager',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Call> calls = [];
@override
void initState() {
super.initState();
load();
}
load() async {
// initially populate calls by getting last value from shared preferences and parsing it
}
persist() async {
// encode calls as json and write to share prefs
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Calls'),
),
body: new ListView(
scrollDirection: Axis.horizontal,
children: calls
.map((call) => new ListTile(
title: new Text(call.phoneNumber),
))
.toList(),
),
floatingActionButton: new FloatingActionButton(
onPressed: () {
Navigator.push<Call>(
context,
new MaterialPageRoute(
builder: (context) => new SecondPage(),
),
).then((newCall) {
if (newCall != null) {
setState(() {
calls.add(newCall);
});
persist();
}
});
},
tooltip: 'New',
child: new Icon(Icons.add),
),
);
}
}