Json 颤振:如何将用户创建的对象存储在本地存储中,并将其检索到ListView中
我正在Flitter中重新创建我的应用程序,我很难存储对象并将其检索到列表中。使用SharedPreferences和GSON在整个Android应用程序中运行良好,但由于flatter中不存在GSON,在我看来,将onject存储为JSON数据是一种可行的方法 流程应如下所示: 用户在AddNewCall屏幕上添加新呼叫。这包括姓名、电话号码和可选说明' 当用户单击“保存”按钮时,将根据这些字段中的文本创建一个调用对象。对象被编码成如下字符串:Json 颤振:如何将用户创建的对象存储在本地存储中,并将其检索到ListView中,json,object,local-storage,storage,flutter,Json,Object,Local Storage,Storage,Flutter,我正在Flitter中重新创建我的应用程序,我很难存储对象并将其检索到列表中。使用SharedPreferences和GSON在整个Android应用程序中运行良好,但由于flatter中不存在GSON,在我看来,将onject存储为JSON数据是一种可行的方法 流程应如下所示: 用户在AddNewCall屏幕上添加新呼叫。这包括姓名、电话号码和可选说明' 当用户单击“保存”按钮时,将根据这些字段中的文本创建一个调用对象。对象被编码成如下字符串:stringjsondata=json.encod
stringjsondata=json.encode(newCallObject)代码>
调用JSON数据使用getApplicationDocumentsDirectory()保存到应用程序的本地存储中。
用户将返回主屏幕,JSON文件将以initState()
方法异步加载到应用程序中。
JSON数据被解码并添加到ListView中
我遇到的问题是,在步骤3将JSON数据添加到文件中时,它将如下所示:{sampleData}{sampleData}
而不是作为一个数组被包围在[]
中。因此,应用程序在读取文件时会打嗝。到目前为止,我的解决方案是将文件内容解析为一个数组,在}{之间插入一个下划线,然后将生成的字符串拆分为一个String类型的数组
String jsonCalls = await file.readAsString();
jsonCalls = jsonCalls.replaceAll('}{', '}_{');
List<String> temp = jsonCalls.split('_');
String jsonCalls=await file.readAsString();
jsonCalls=jsonCalls.replaceAll('}{','}{');
List temp=jsonCalls.split(“”);
所以现在我得到了一个包含JSON字符串的数组,但我一直坚持能够访问每个JSON字符串中的值。我采用的整个方法似乎也太复杂了。肯定有更好的方法,但我疯狂地在谷歌上搜索,什么也没找到。你们能帮我吗
谢谢!这里有一些建议
Flatter支持使用共享的首选项,所以它应该对Android很熟悉
initState
仅在第一次初始化StatefulWidget时调用,因此可能不是期望重新加载更改信息的好地方
考虑将您的工作状态保留在内存中,例如在列表中,您可以随时向其中添加新呼叫
当您将此列表
序列化为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),
),
);
}
}
类MyApp扩展了无状态小部件{
@凌驾
小部件构建(构建上下文){
返回新材料PP(
标题:“呼叫经理”,
主题:新主题数据(
主样本:颜色。蓝色,
),
主页:新建MyHomePage(),
);
}
}
类MyHomePage扩展StatefulWidget{
@凌驾
_MyHomePageState createState()=>new_MyHomePageState();
}
类_MyHomePageState扩展状态{
列表调用=[];
@凌驾
void initState(){
super.initState();
加载();
}
load()异步{
//最初通过从共享首选项中获取最后一个值并对其进行解析来填充调用
}
persist()异步{
//将调用编码为json并写入共享pref
}
@凌驾
小部件构建(构建上下文){
归还新脚手架(
appBar:新的appBar(
标题:新文本(“调用”),
),
正文:新列表视图(
滚动方向:轴水平,
儿童:电话
.map((调用)=>新建ListTile(
标题:新文本(call.phoneNumber),
))
.toList(),
),
floatingActionButton:新的floatingActionButton(
已按下:(){
导航器。推(
上下文
新材料路线(
生成器:(上下文)=>新建第二页(),
),
).然后((newCall){
if(newCall!=null){
设置状态(){
调用。添加(newCall);
});
坚持();
}
});
},
工具提示:“新建”,
子:新图标(Icons.add),
),
);
}
}
1.是的,但据我所知,Flatter中的SharedReferences不会存储对象2.不知道initState()的这一点,谢谢!3.不确定我将如何实现此建议。我将如何在屏幕之间跟踪此列表?1它将存储一个字符串,这是json.encode提供给您的。3您可以将列表保持在主页的状态。如果使用Navigator.push启动第二个页面,则当seco第二页关闭。这可能是第二页的结果,您可以将其添加到列表中。您是说列表将是一个全局变量?不,是主页状态的一部分。