iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
自我挑戰組

30天學習flutter系列 第 19

19.flutter的持久化存儲(二)

  • 分享至 

  • xImage
  •  

我們今天來使用shared_preferences

添加我們的依賴[/shared_preferences)](https://pub.dev/packages/shared_preferences)

dependencies:
  shared_preferences: ^2.0.15

簡單介紹Link

Readme
Changelog
Example
Installing
Versions
Scores
Shared preferences plugin
pub package

Wraps platform-specific persistent storage for simple data (NSUserDefaults on iOS and macOS, SharedPreferences on Android, etc.). Data may be persisted to disk asynchronously, and there is no guarantee that writes will be persisted to disk after returning, so this plugin must not be used for storing critical data.

Supported data types are int, double, bool, String and List.

Android iOS Linux macOS Web Windows
Support SDK 16+ 9.0+ Any 10.11+ Any Any
Usage
To use this plugin, add shared_preferences as a dependency in your pubspec.yaml file.

Examples
Here are small examples that show you how to use the API.

提供的data type為 int、double、bool、String 和 List<String>

  • 寫入data
// 獲取shared preferences.
final prefs = await SharedPreferences.getInstance();

// 將字符串列表保存到 'items' 鍵
await prefs.setStringList('items', <String>['Earth', 'Moon', 'Sun']);
  • 讀取data
// 嘗試從 'counter' 鍵讀取數據。如果不存在,則返回 null
final int? counter = prefs.getInt('counter');

// 嘗試從“items”鍵讀取數據。如果不存在,則返回 null
final List<String>? items = prefs.getStringList('items');
  • 移除entry
// 刪除“counter”鍵的data
final success = await prefs.remove('counter');

練習,我們嘗試創建user state
https://ithelp.ithome.com.tw/upload/images/20221004/20108931OGvpOHjezZ.png

lib\models\user_model.dart

// To parse this JSON data, do
//
//     final userModel = userModelFromMap(jsonString);

import 'package:meta/meta.dart';
import 'dart:convert';

class UserModel {
  UserModel({
    required this.username,
    required this.isLogin,
    required this.bio,
    required this.email,
    required this.message,
  });

  final String username;
  final bool isLogin;
  final String bio;
  final String email;
  final String message;

  UserModel copyWith({
    String? username,
    bool? isLogin,
    String? bio,
    String? email,
    String? message,
  }) =>
      UserModel(
        username: username ?? this.username,
        isLogin: isLogin ?? this.isLogin,
        bio: bio ?? this.bio,
        email: email ?? this.email,
        message: message ?? this.message,
      );

  factory UserModel.fromJson(String str) => UserModel.fromMap(json.decode(str));

  String toJson() => json.encode(toMap());

  factory UserModel.fromMap(Map<String, dynamic> json) => UserModel(
        username: json["username"],
        isLogin: json["isLogin"],
        bio: json["bio"],
        email: json["email"],
        message: json["message"],
      );

  Map<String, dynamic> toMap() => {
        "username": username,
        "isLogin": isLogin,
        "bio": bio,
        "email": email,
        "message": message,
      };
}

lib\states\Iuser_state.dart

import 'package:todo/models/todo_model.dart';
import 'package:todo/models/user_model.dart';

abstract class IUserState {
  void register(UserModel user);
  void login(UserModel user);
  void logout();
}

lib\states\user_state.dart

import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/models/user_model.dart';
import 'package:todo/states/Iuser_state.dart';

class UserState extends StateNotifier<UserModel> implements IUserState {
  UserState(UserModel? userModel)
      : super(
          userModel ??
              UserModel(
                  username: "",
                  isLogin: false,
                  bio: "",
                  email: "",
                  message: ""),
        );

  @override
  void login(UserModel user) {
    // TODO: implement login
    state = state.copyWith(
      username: user.username,
      isLogin: true,
      bio: user.bio,
      email: user.email,
    );
  }

  @override
  void logout() {
    // TODO: implement logout
    state = state.copyWith(
      username: "",
      isLogin: false,
      bio: "",
      email: "",
    );
  }

  @override
  void register(UserModel user) {
    // TODO: implement register
  }
}

final userProvider = StateNotifierProvider<UserState, UserModel>((ref) {
  return UserState();
});

我們將加入shared_preferences到我們login和logout的功能

  @override
  void login(UserModel user) async {
    // TODO: implement login
    final prefs = await SharedPreferences.getInstance();

    if (prefs.getBool('isLogin') == null) {
      await prefs.setBool('isLogin', false);
    }

    if (user.isLogin == false) {
      state = state.copyWith(
        username: user.username,
        isLogin: true,
        bio: user.bio,
        email: user.email,
        message: "Login success",
      );
      await prefs.setBool('isLogin', true);
    }
  }

  @override
  void logout() async {
    // TODO: implement logout
    final prefs = await SharedPreferences.getInstance();

    if (prefs.getBool('isLogin') == null) {
      await prefs.setBool('isLogin', false);
    }

    if (prefs.getBool('isLogin') == true) {
      state = state.copyWith(
        username: "",
        isLogin: false,
        bio: "",
        email: "",
        message: "Logout success",
      );
      await prefs.setBool('isLogin', false);
    }
  }

接著,打開我們的lib\ui\widgets\user_header_widget.dart
加入state manager

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:todo/models/user_model.dart';
import 'package:todo/states/user_state.dart';

class UserHeader extends ConsumerWidget {
  const UserHeader({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    UserModel _testUser = UserModel(
      username: 'username',
      isLogin: false,
      bio: 'bio',
      email: 'email@test.com',
      message: '',
    );

    bool isLogin = ref.watch(userProvider).isLogin;
    String message = ref.watch(userProvider).message;

    return Container(
      child: Row(children: [
        Placeholder(
          fallbackHeight: 50,
          fallbackWidth: 50,
        ),
        const SizedBox(
          width: 20,
        ),
        isLogin
            ? Column(
                children: [
                  Text('username: ' + ref.watch(userProvider).username),
                  Text('bio: ' + ref.watch(userProvider).bio),
                  Text('email: ' + ref.watch(userProvider).email),
                  TextButton(
                    onPressed: () {
                      ref.read(userProvider.notifier).logout();
                      print(message);
                    },
                    child: Text('Logout'),
                  )
                ],
              )
            : ElevatedButton(
                onPressed: () {
                  ref.read(userProvider.notifier).login(_testUser);
                  print(message);
                },
                child: Text('Login'),
              ),
      ]),
    );
  }
}

並修改lib\ui\screens\user_screen.dart

class UserScreen extends StatefulWidget {
  const UserScreen({Key? key}) : super(key: key);

  @override
  State<UserScreen> createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {
  final TrackingScrollController _trackingScrollController =
      TrackingScrollController();

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      controller: _trackingScrollController,
      slivers: [
        SliverAppBar(
          title: Text('User Screen'),
        ),
        SliverToBoxAdapter(
          child: Container(
            padding: const EdgeInsets.all(8.0),
            child: UserHeader(),
          ),
        ),
      ],
    );
  }
}

並且我們測試一下
app-test.gif


上一篇
18.flutter的持久化存儲(一)
下一篇
20.flutter的持久化存儲(三)
系列文
30天學習flutter30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
kevenand
iT邦新手 5 級 ‧ 2023-03-21 16:22:35

请问下关闭软件再打开,登录状态失效怎么解决呢?

0
kevenand
iT邦新手 5 級 ‧ 2023-03-21 16:27:03

我感觉你使用shared_preferences缓存还是没有解决一个问题,那就是打开app的时候从缓存获取数据存到state中

我要留言

立即登入留言