preface
Just like iOS and Android, Flutter also has many types of persistent storage, such as key-value storage, file storage, database storage, etc. In essence, Flutter is implemented by the corresponding module of the platform. In this article we will take you through the application of key-value storage.
Key-value storage is introduced
Key-value storage mainly refers to the specific API provided by the platform for us to operate. The essence of key-value storage is still to store data in specific files, but these work are done by the platform for us, such as NSUserDefaults in iOS platform, SharedPreferences in Android platform, etc. The shared_preferences plugin can be used to store key-values in Flutter. The main data types stored in Flutter include bool, int, double, String, List, and so on.
Key-value storage usage
The introduction of the plugin
Add the shared_preferences plug-in to the pubspec.yaml file as follows:
dependencies:
flutter:
sdk: flutter
# shared_preferences plug-inShared_preferences: 0.4.3Copy the code
Then run the flutter Packages get command to download the plugin locally
Method of use
After the plug-in is introduced into the project, import the shared_preferences. Dart file in the dart file you use
import 'package:shared_preferences/shared_preferences.dart';
Copy the code
The singleton method for obtaining SharedPreferences is an asynchronous method, so we need to use await to obtain the real object as follows:
Future<SharedPreferences> _prefs = SharedPreferences.getInstance(); // Save data void saveMethodName() async {SharedPreferences prefs = await _prefs; prefs.setString("strKey"."strValue");
prefs.setInt("intKey"."intValue"); Void initFromCache() async {SharedPreferences prefs = await _prefs; String strValue = prefs.getString("strKey");
int intValue = prefs.getInt("intKey"); ...}Copy the code
Take a chestnut
import 'package:shared_preferences/shared_preferences.dart';
class TestPersistent extends StatefulWidget {
final String title;
TestPersistent({Key key, this.title}):super(key: key);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return TestPersistentState();
}
}
class TestPersistentState extends State<TestPersistent> {
var controller = TextEditingController();
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
bool mt = false;
bool ds = false;
bool ltb = false;
@override
void initState() {
// TODO: implement initState
super.initState();
initFromCache();
}
@override
void dispose() { super.dispose(); controller = null; } void initFromCache() async {final SharedPreferences prefs = await _prefs; final nickname = prefs.getString("nickname");
final mt = prefs.getBool("mt");
final ds = prefs.getBool("ds");
final ltb = prefs.getBool("ltb"); // After obtaining the value in the cache, usesetState Updates interface informationsetState(() {
controller.text = (nickname == null ? "" : nickname);
this.mt = (mt == null ? false : mt);
this.ds = (ds == null ? false : ds);
this.ltb = (ltb == null ? false: ltb); }); } void saveInfo(String nickname) async {final SharedPreferences prefs = await _prefs; prefs.setString("nickname", nickname);
prefs.setBool("mt", mt);
prefs.setBool("ds", ds);
prefs.setBool("ltb", ltb);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(this.widget.title),
),
body: Container(
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
TextField(
controller: controller,
decoration: InputDecoration(
labelText: 'Nickname:',
hintText: 'Please input nickname',
),
),
Text('What new social software have you used recently?'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('toilet MT'),
Switch(
value: mt,
onChanged: (isChanged) {
setState(() {
this.mt = isChanged;
});
},
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('more flash'),
Switch(
value: ds,
onChanged: (isChanged) {
setState(() {
this.ds = isChanged;
});
},
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(Chatbot),
Switch(
value: ltb,
onChanged: (isChanged) {
setState(() {
this.ltb = isChanged;
});
},
)
],
),
MaterialButton(
child: Text('save'),
onPressed: () {
print(controller.text); saveInfo(controller.text); },),],),); }}Copy the code
The running effect is as follows:
Shared-preferences Implementation principle
The implementation principle of the plug-in is very simple. Through source code analysis, we found that it is mainly through channel to interact with the native platform, through iOS platform NSUserDefaults, Android platform SharedPreferences to achieve specific data access operations.
IOS Platform Analysis
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:CHANNEL_NAME binaryMessenger:registrar.messenger]; [channelsetMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
NSString *method = [call method];
NSDictionary *arguments = [call arguments];
if ([method isEqualToString:@"getAll"]) {
result(getAllPrefs());
} else if ([method isEqualToString:@"setBool"]) {
NSString *key = arguments[@"key"];
NSNumber *value = arguments[@"value"];
[[NSUserDefaults standardUserDefaults] setBool:value.boolValue forKey:key];
result(@YES);
} else if ([method isEqualToString:@"setInt"]) {
NSString *key = arguments[@"key"];
NSNumber *value = arguments[@"value"];
// int type in Dart can come to native side in a variety of forms
// It is best to store it as is and send it back when needed.
// Platform channel will handle the conversion.
[[NSUserDefaults standardUserDefaults] setValue:value forKey:key];
result(@YES);
} else{..}}]; }Copy the code
It can be seen from the source code that the code of FLUTTER transmits the specified method and corresponding stored data to the iOS platform. Upon receiving the command data, the iOS terminal will determine the type of operation to be performed according to the method name and then perform corresponding operations. SetBool, for example, holds data of type bool in [NSUserDefaults standardUserDefaults] objects.
The android platform
private final android.content.SharedPreferences preferences; public static void registerWith(PluginRegistry.Registrar registrar) { MethodChannel channel = new MethodChannel(registrar.messenger(), CHANNEL_NAME); SharedPreferencesPlugin instance = new SharedPreferencesPlugin(registrar.context()); channel.setMethodCallHandler(instance); } private SharedPreferencesPlugin(Context context) { preferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); } @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { String key = call.argument("key");
boolean status = false;
try {
switch (call.method) {
case "setBool":
status = preferences.edit().putBoolean(key, (boolean) call.argument("value")).commit();
break;
case "setDouble":
float floatValue = ((Number) call.argument("value")).floatValue();
status = preferences.edit().putFloat(key, floatValue).commit();
break;
.
.
.
}
result.success(status);
} catch (IOException e) {
result.error("IOException encountered", call.method, e); }}Copy the code
The Android terminal is similar to the iOS terminal. It uses a SharedPreferences instance object to access data according to the specified Method.
Write in the last
Key-value is mainly used to store some simple configuration information or state data. Lightweight data persistence is very suitable for data storage scenarios with large order of magnitude. We are going to use file storage and database storage, next we will take you to learn file storage, please look forward to!
Description:
This article is reprinted from the corresponding “Flutter Programming Guide” wechat official account. For more Flutter related articles, open our wechat and scan our QR code to follow our wechat official account.