Home > Back-end >  Load List with SharedPreferences -> Unhandled Exception: type 'Null' is not a subtype o
Load List with SharedPreferences -> Unhandled Exception: type 'Null' is not a subtype o

Time:07-01

I am learning how to use the SharedPreferences library in Flutter.

I created the code below as a test to see how I can save and load a List.

When I do a hot restart, the list does not load correctly. I have this error:

E/flutter (17671): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'List<Row>'
E/flutter (17671): #0      new Data.fromJson (package:plus1/data.dart:25:5)
E/flutter (17671): #1      _MyHomePageState.loadData.<anonymous closure> (package:plus1/main2.dart:62:27)
E/flutter (17671): #2      State.setState (package:flutter/src/widgets/framework.dart:1121:30)
E/flutter (17671): #3      _MyHomePageState.loadData (package:plus1/main2.dart:53:5)
E/flutter (17671): <asynchronous suspension>

This is my code:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'data.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int counter = 0;
  int counter2 = 0;
  List<Row> chatMessages = [];

  increment() {
    setState(() {
      counter  = 1;
      counter2  = 2;
      chatMessages.add(Row());

      print('LenghtOfList: ${chatMessages.length}');
    });
  }

  loadData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    setState(() {
      String? json = prefs.getString('UserData');
      print('loaded json: $json');

      if (json == null) {
        print('NO DATA (null)');
      } else {
        Map<String, dynamic> map = jsonDecode(json);
        print('map $map');
        final data = Data.fromJson(map);
        print('Data ${data.counter}, ${data.counter2}');

        counter = data.counter;
        counter2 = data.counter2;
        chatMessages = data.chatMessages;
      }
    });
  }

  saveData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    final _data = Data(
      counter: counter,
      counter2: counter2,
      chatMessages: chatMessages,
    );

    String json = jsonEncode(_data);
    print('saved json: $json');
    prefs.setString('UserData', json);
  }

  clearData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.clear();
    print('data cleared');
  }

  /// dichiarare l' initState()
  @override
  void initState() {
    super.initState();
    loadData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              'c: $counter, c2: $counter2',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          increment();
          saveData();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

import 'package:flutter/material.dart';

class Data {
  int counter = 0;
  int counter2 = 0;
  List<Row> chatMessages = [];

  Data({
    required this.counter,
    required this.counter2,
    required this.chatMessages,
  });

  Map<String, dynamic> toJson() {
    return {
      'counter': counter,
      'counter2': counter2,
      'chatMessages': chatMessages,
    };
  }

  Data.fromJson(Map<String, dynamic> json) {
    counter = json['counter'];
    counter2 = json['counter2'];
    chatMessages = json['chatMessages'];
  }
}

Can anyone explain why it doesn't work and how I can fix it?

Thank you.

CodePudding user response:

You need to expect the List can be null (empty) in some scenarios, in this case you need to declare the list as nullable, use

List<Rows>? chatMessages = [];

Also, you are not processing the json data of chatMessages to the Row type. using fromJson and toJson is recommended only for basic conversions, if you have complex structure, you need to use proper JSON serializers. I would recommend using https://pub.dev/packages/json_serializable

  • Related