As always these simplest solutions are the hardest for me to solve. I have the ImagePicker function to get image from gallery and set it as a background. The code below works perfectly, but the image doesn't save, so after each restart, it isn't there. Here's the code:

Future _getImage() async {
final picker = ImagePicker();

final pickedFile = await picker.getImage(source: ImageSource.gallery);

setState(() {
  if (pickedFile != null) {
    _image = File(pickedFile.path);

    print('_image: $_image');
  } else {
    print('No image selected');
  }
});

}

So my question is how to save the image for it to be permanent and persist after restarts, I have tried everything (setting and saving paths etc) and for some reason can't get it to work. Hopefully the solution is simple. My understanding is it should be saved to local storage of the device, in this case the emulator, but it should work on every device of course.


Solution 1: Will Hlas

There's probably a better way to do this, but here's a working example using shared preferences :

import 'dart:io';

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

void main() async {
  runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()));
}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  String filePath = '';

  getImage() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool check = prefs.containsKey('image');
    if (check) {
      setState(() {
        filePath = prefs.getString('image');
      });
      return;
    }
    ImagePicker imagePicker = new ImagePicker();
    PickedFile image = await imagePicker.getImage(source: ImageSource.gallery);
    String imagePath = image.path;
    await prefs.setString('image', imagePath);
    setState(() {
      filePath = prefs.getString('image');
    });
  }

  @override
  void initState() {
    super.initState();
    getImage();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Container(
        child: filePath == '' ? FlatButton(
          onPressed: getImage,
          child: Text('get image'),
        ) : Image.file(File(filePath)),
      )
    );
  }
}


Solution 2: morpheus

You can save the image that is picked from the gallery by the user to the application directory. Then, use this image to show from the local storage.

  1. Get the directory path using path_provider

    Directory appDocDir = await getApplicationDocumentsDirectory();
    String appDocPath = appDocDir.path;
    
  2. Save image to your directory

    final picker = ImagePicker();
    
    final pickedFile = await picker.getImage(source: ImageSource.gallery);
    
    if (pickedFile == null) return;
    
    _image = File(pickedFile.path);
    
    final fileName = 'background_image';
    final File localImage = await _image.copy('${widget.appDocPath}/$fileName');
    
  3. Use the image in your widget tree

    Image image;
    var hasLocalImage =
        File('${widget.appDocPath}/background_image').existsSync();
    if (hasLocalImage) {
      var bytes =
          File('${widget.appDocPath}/background_image').readAsBytesSync();
      image = Image.memory(bytes);
    }
    

Full working example:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SplashScreen(),
    );
  }
}

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  String appDocPath;

  Future<void> getApplicationDirectoryPath() async {
    Directory appDocDir = await getApplicationDocumentsDirectory();
    appDocPath = appDocDir.path;
  }

  @override
  initState() {
    getApplicationDirectoryPath().then((_) {
      Navigator.pushReplacement(
          context,
          MaterialPageRoute(
              builder: (BuildContext context) => Home(
                    appDocPath,
                  )));
    });

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

class Home extends StatefulWidget {
  final String appDocPath;

  Home(this.appDocPath);
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  File _image;

  @override
  initState() {
    super.initState();
  }

  Future _getImage() async {
    final picker = ImagePicker();

    final pickedFile = await picker.getImage(source: ImageSource.gallery);

    if (pickedFile == null) return;

    _image = File(pickedFile.path);

    final fileName = 'background_image';
    final File localImage = await _image.copy('${widget.appDocPath}/$fileName');

    setState(() {
    });
  }

  @override
  Widget build(BuildContext context) {
    Image image;
    var hasLocalImage =
        File('${widget.appDocPath}/background_image').existsSync();
    if (hasLocalImage) {
      var bytes =
          File('${widget.appDocPath}/background_image').readAsBytesSync();
      image = Image.memory(bytes);
    }

    return new Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            _getImage();
          },
        ),
        body: (File('${widget.appDocPath}/background_image').existsSync())
            ? Center(
                child: image,
              )
            : Text('NO PICTURE HAS BEEN SELECTED NOW OR IN THE PAST'));
  }
}