ImagePicker PlatformException that occurs only on packaged build - android

I'm building a simple flutter app, which needs to takes pictures. For that i'm using ImagePicker.
When built into an APK, an error is returned when _getImage is called:
"Pick image error.PlatformException(error,null,null)[...]"
When executed through flutter run on the same device, it works as expected.
Relevant part of the code:
class _BodyState extends State<Body> {
final ImagePicker _picker = ImagePicker();
XFile? _imageFile;
dynamic _pickImageError;
String? _retrieveDataError;
void _getImage(ImageSource source) async {
try {
final pickedFile = await _picker.pickImage(
source: source,
maxWidth: 720,
maxHeight: 1280,
imageQuality: 80,
// preferredCameraDevice: CameraDevice.rear,
);
setState(() {
_imageFile = pickedFile;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
}
Widget _previewImages() {
final Text? retrieveError = _getRetrieveErrorWidget();
Size size = MediaQuery.of(context).size;
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
return CircleAvatar(
backgroundColor: Colors.transparent,
radius: 150,
backgroundImage: FileImage(File(_imageFile!.path)),
);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return CircleAvatar(
backgroundColor: Colors.transparent,
radius: 150,
child: Image.asset(
"assets/images/user.png",
width: size.width,
),
);
}
}
Text? _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError!);
_retrieveDataError = null;
return result;
}
return null;
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
_imageFile = response.file;
});
} else {
_retrieveDataError = response.exception!.code;
}
}
#override
Widget build(BuildContext context) {
return Background(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _previewImages();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
//: _previewImages(),
),
Error log (couldn't copy it)
How it should look like

Related

Flutter Full page ads in PageView like Short news Way2news

Hello Everyone I want to show Admob ads in my flutter pageview after a 5-page swipe and on the 6th page I want a full-page banner ad, if I swipe this then I can go on the 7th page of the news.
I have implemented but I am unable to get full-page banner ads, it shows 312x100 pixels size ads only.
Here is my full code.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'Helper/ad_helper.dart';
import 'Models/news.dart';
import 'package:http/http.dart' as http;
class Tedd extends StatefulWidget {
#override
_TeddState createState() => _TeddState();
}
class _TeddState extends State<Tedd> {
List<NewsModel> _newsList = [];
bool isLoading = true;
late BannerAd _bannerAd;
bool _isBannerAdReady = false;
int currentPage = 1;
bool hasReachedEnd = false;
PageController _pageController = PageController(initialPage: 0);
_getAllNews(currentPage) async {
var articles = await http.get(Uri.parse(
"https://pkbhai.com/myprojects/kids-stories/api/all-stories?page=${currentPage}"));
var result = json.decode(articles.body);
var newDataLength = result['data'].length;
if (newDataLength == 0) {
setState(() {
hasReachedEnd = true;
});
}
result['data'].forEach((data) {
var news = NewsModel();
news.id = data["id"];
news.articleTitle = data["name"];
news.articleDetails = data["details"];
if (mounted) {
setState(() {
_newsList.add(news);
});
}
});
setState(() {
isLoading = true;
});
}
void handleNext() {
_pageController.addListener(() async {
if (_pageController.page?.toInt() == _newsList.length - 1) {
setState(() {
currentPage += 1;
});
_getAllNews(currentPage);
}
});
}
#override
void initState() {
_bannerAd = BannerAd(
adUnitId: AdHelper.bannerAdUnitId,
request: AdRequest(),
size: AdSize.banner,
listener: BannerAdListener(
onAdLoaded: (_) {
setState(() {
_isBannerAdReady = true;
});
},
onAdFailedToLoad: (ad, err) {
print('Failed to load a banner ad: ${err.message}');
_isBannerAdReady = false;
ad.dispose();
},
),
);
_bannerAd.load();
_getAllNews(currentPage);
handleNext();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _newsList.length > 0
? PageView.builder(
scrollDirection: Axis.vertical,
controller: _pageController,
itemCount: _newsList.length + (isLoading ? 1 : 0),
itemBuilder: (context, index) {
if (index == _newsList.length && hasReachedEnd) {
return Container(
color: Colors.red,
);
}
if (index == _newsList.length && !hasReachedEnd) {
return Center(
child: CircularProgressIndicator(),
);
}
if (index % 5 == 0 && index != 0) {
return Container(
child:
// if (_isBannerAdReady)
Align(
alignment: Alignment.topCenter,
child: Container(
width: _bannerAd.size.width.toDouble(),
height: _bannerAd.size.height.toDouble(), // also tried 1000, but not worked
child: AdWidget(ad: _bannerAd),
),
),
);
}
return Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: Colors.blue.shade400,
height: MediaQuery.of(context).size.height,
child: PageView(
reverse: true,
children: [
Text(
_newsList[index].articleDetails!,
maxLines: 4,
),
Text(_newsList[index].articleTitle!),
],
),
),
),
);
},
)
: Center(child: CircularProgressIndicator()),
);
}
}

flutter_downloader, how do I get the values of url and filename from firebase into this flow and add to the list of download tasks?

I want to pass the values like name and link in the below code's final variables dynamically i.e when onPressed is executed. Any help would be appreciated... I have separated the section using ----- below.
In the example below all files have their names and links hardcoded which is less efficient and I want to pass these values dynamically and only when a user clicks on the required button
import 'dart:isolate';
import 'dart:ui';
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:permission_handler/permission_handler.dart';
const debug = true;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterDownloader.initialize(debug: debug);
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final platform = Theme.of(context).platform;
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(
title: 'Downloader',
platform: platform,
),
);
}
}
class MyHomePage extends StatefulWidget with WidgetsBindingObserver {
final TargetPlatform platform;
MyHomePage({Key key, this.title, this.platform}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
---------------------------------------------------------------------------------------
final _documents = [
{
'name': 'Learning Android Studio',
'link':
'http://barbra-coco.dyndns.org/student/learning_android_studio.pdf'
},
{
'name': 'Android Programming Cookbook',
'link':
'http://enos.itcollege.ee/~jpoial/allalaadimised/reading/Android-Programming-Cookbook.pdf'
},
{
'name': 'iOS Programming Guide',
'link':
'http://darwinlogic.com/uploads/education/iOS_Programming_Guide.pdf'
},
{
'name': 'Objective-C Programming (Pre-Course Workbook',
'link':
'https://www.bignerdranch.com/documents/objective-c-prereading-assignment.pdf'
},
];
final _images = [
{
'name': 'Arches National Park',
'link':
'https://upload.wikimedia.org/wikipedia/commons/6/60/The_Organ_at_Arches_National_Park_Utah_Corrected.jpg'
},
{
'name': 'Canyonlands National Park',
'link':
'https://upload.wikimedia.org/wikipedia/commons/7/78/Canyonlands_National_Park%E2%80%A6Needles_area_%286294480744%29.jpg'
},
{
'name': 'Death Valley National Park',
'link':
'https://upload.wikimedia.org/wikipedia/commons/b/b2/Sand_Dunes_in_Death_Valley_National_Park.jpg'
},
{
'name': 'Gates of the Arctic National Park and Preserve',
'link':
'https://upload.wikimedia.org/wikipedia/commons/e/e4/GatesofArctic.jpg'
}
];
final _videos = [
{
'name': 'Big Buck Bunny',
'link':
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
},
{
'name': 'Elephant Dream',
'link':
'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4'
}
];
-------------------------------------------------------------------------------------------
List<_TaskInfo> _tasks;
List<_ItemHolder> _items;
bool _isLoading;
bool _permissionReady;
String _localPath;
ReceivePort _port = ReceivePort();
#override
void initState() {
super.initState();
_bindBackgroundIsolate();
FlutterDownloader.registerCallback(downloadCallback);
_isLoading = true;
_permissionReady = false;
_prepare();
}
#override
void dispose() {
_unbindBackgroundIsolate();
super.dispose();
}
void _bindBackgroundIsolate() {
bool isSuccess = IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
if (!isSuccess) {
_unbindBackgroundIsolate();
_bindBackgroundIsolate();
return;
}
_port.listen((dynamic data) {
if (debug) {
print('UI Isolate Callback: $data');
}
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
final task = _tasks?.firstWhere((task) => task.taskId == id);
if (task != null) {
setState(() {
task.status = status;
task.progress = progress;
});
}
});
}
void _unbindBackgroundIsolate() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
}
static void downloadCallback(
String id, DownloadTaskStatus status, int progress) {
if (debug) {
print(
'Background Isolate Callback: task ($id) is in status ($status) and process ($progress)');
}
final SendPort send =
IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Builder(
builder: (context) => _isLoading
? new Center(
child: new CircularProgressIndicator(),
)
: _permissionReady
? _buildDownloadList()
: _buildNoPermissionWarning()),
);
}
Widget _buildDownloadList() => Container(
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 16.0),
children: _items
.map((item) => item.task == null
? _buildListSection(item.name)
: DownloadItem(
data: item,
onItemClick: (task) {
_openDownloadedFile(task).then((success) {
if (!success) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('Cannot open this file')));
}
});
},
onAtionClick: (task) {
if (task.status == DownloadTaskStatus.undefined) {
_requestDownload(task);
} else if (task.status == DownloadTaskStatus.running) {
_pauseDownload(task);
} else if (task.status == DownloadTaskStatus.paused) {
_resumeDownload(task);
} else if (task.status == DownloadTaskStatus.complete) {
_delete(task);
} else if (task.status == DownloadTaskStatus.failed) {
_retryDownload(task);
}
},
))
.toList(),
),
);
Widget _buildListSection(String title) => Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Text(
title,
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.blue, fontSize: 18.0),
),
);
Widget _buildNoPermissionWarning() => Container(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Text(
'Please grant accessing storage permission to continue -_-',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.blueGrey, fontSize: 18.0),
),
),
SizedBox(
height: 32.0,
),
FlatButton(
onPressed: () {
_checkPermission().then((hasGranted) {
setState(() {
_permissionReady = hasGranted;
});
});
},
child: Text(
'Retry',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
fontSize: 20.0),
))
],
),
),
);
void _requestDownload(_TaskInfo task) async {
task.taskId = await FlutterDownloader.enqueue(
url: task.link,
headers: {"auth": "test_for_sql_encoding"},
savedDir: _localPath,
showNotification: true,
openFileFromNotification: true);
}
void _cancelDownload(_TaskInfo task) async {
await FlutterDownloader.cancel(taskId: task.taskId);
}
void _pauseDownload(_TaskInfo task) async {
await FlutterDownloader.pause(taskId: task.taskId);
}
void _resumeDownload(_TaskInfo task) async {
String newTaskId = await FlutterDownloader.resume(taskId: task.taskId);
task.taskId = newTaskId;
}
void _retryDownload(_TaskInfo task) async {
String newTaskId = await FlutterDownloader.retry(taskId: task.taskId);
task.taskId = newTaskId;
}
Future<bool> _openDownloadedFile(_TaskInfo task) {
return FlutterDownloader.open(taskId: task.taskId);
}
void _delete(_TaskInfo task) async {
await FlutterDownloader.remove(
taskId: task.taskId, shouldDeleteContent: true);
await _prepare();
setState(() {});
}
Future<bool> _checkPermission() async {
if (widget.platform == TargetPlatform.android) {
final status = await Permission.storage.status;
if (status != PermissionStatus.granted) {
final result = await Permission.storage.request();
if (result == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
} else {
return true;
}
return false;
}
Future<Null> _prepare() async {
final tasks = await FlutterDownloader.loadTasks();
int count = 0;
_tasks = [];
_items = [];
_tasks.addAll(_documents.map((document) =>
_TaskInfo(name: document['name'], link: document['link'])));
_items.add(_ItemHolder(name: 'Documents'));
for (int i = count; i < _tasks.length; i++) {
_items.add(_ItemHolder(name: _tasks[i].name, task: _tasks[i]));
count++;
}
_tasks.addAll(_images
.map((image) => _TaskInfo(name: image['name'], link: image['link'])));
_items.add(_ItemHolder(name: 'Images'));
for (int i = count; i < _tasks.length; i++) {
_items.add(_ItemHolder(name: _tasks[i].name, task: _tasks[i]));
count++;
}
_tasks.addAll(_videos
.map((video) => _TaskInfo(name: video['name'], link: video['link'])));
_items.add(_ItemHolder(name: 'Videos'));
for (int i = count; i < _tasks.length; i++) {
_items.add(_ItemHolder(name: _tasks[i].name, task: _tasks[i]));
count++;
}
tasks?.forEach((task) {
for (_TaskInfo info in _tasks) {
if (info.link == task.url) {
info.taskId = task.taskId;
info.status = task.status;
info.progress = task.progress;
}
}
});
_permissionReady = await _checkPermission();
_localPath = (await _findLocalPath()) + Platform.pathSeparator + 'Download';
final savedDir = Directory(_localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
setState(() {
_isLoading = false;
});
}
Future<String> _findLocalPath() async {
final directory = widget.platform == TargetPlatform.android
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
return directory.path;
}
}
class DownloadItem extends StatelessWidget {
final _ItemHolder data;
final Function(_TaskInfo) onItemClick;
final Function(_TaskInfo) onAtionClick;
DownloadItem({this.data, this.onItemClick, this.onAtionClick});
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 16.0, right: 8.0),
child: InkWell(
onTap: data.task.status == DownloadTaskStatus.complete
? () {
onItemClick(data.task);
}
: null,
child: Stack(
children: <Widget>[
Container(
width: double.infinity,
height: 64.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: Text(
data.name,
maxLines: 1,
softWrap: true,
overflow: TextOverflow.ellipsis,
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: _buildActionForTask(data.task),
),
],
),
),
data.task.status == DownloadTaskStatus.running ||
data.task.status == DownloadTaskStatus.paused
? Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: LinearProgressIndicator(
value: data.task.progress / 100,
),
)
: Container()
].where((child) => child != null).toList(),
),
),
);
}
Widget _buildActionForTask(_TaskInfo task) {
if (task.status == DownloadTaskStatus.undefined) {
return RawMaterialButton(
onPressed: () {
onAtionClick(task);
},
child: Icon(Icons.file_download),
shape: CircleBorder(),
constraints: BoxConstraints(minHeight: 32.0, minWidth: 32.0),
);
} else if (task.status == DownloadTaskStatus.running) {
return RawMaterialButton(
onPressed: () {
onAtionClick(task);
},
child: Icon(
Icons.pause,
color: Colors.red,
),
shape: CircleBorder(),
constraints: BoxConstraints(minHeight: 32.0, minWidth: 32.0),
);
} else if (task.status == DownloadTaskStatus.paused) {
return RawMaterialButton(
onPressed: () {
onAtionClick(task);
},
child: Icon(
Icons.play_arrow,
color: Colors.green,
),
shape: CircleBorder(),
constraints: BoxConstraints(minHeight: 32.0, minWidth: 32.0),
);
} else if (task.status == DownloadTaskStatus.complete) {
return Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'Ready',
style: TextStyle(color: Colors.green),
),
RawMaterialButton(
onPressed: () {
onAtionClick(task);
},
child: Icon(
Icons.delete_forever,
color: Colors.red,
),
shape: CircleBorder(),
constraints: BoxConstraints(minHeight: 32.0, minWidth: 32.0),
)
],
);
} else if (task.status == DownloadTaskStatus.canceled) {
return Text('Canceled', style: TextStyle(color: Colors.red));
} else if (task.status == DownloadTaskStatus.failed) {
return Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text('Failed', style: TextStyle(color: Colors.red)),
RawMaterialButton(
onPressed: () {
onAtionClick(task);
},
child: Icon(
Icons.refresh,
color: Colors.green,
),
shape: CircleBorder(),
constraints: BoxConstraints(minHeight: 32.0, minWidth: 32.0),
)
],
);
} else {
return null;
}
}
}
class _TaskInfo {
final String name;
final String link;
String taskId;
int progress = 0;
DownloadTaskStatus status = DownloadTaskStatus.undefined;
_TaskInfo({this.name, this.link});
}
class _ItemHolder {
final String name;
final _TaskInfo task;
_ItemHolder({this.name, this.task});
}

Cannot build because the frawework is already building - Flutter

I want to show AlertDialog on click of drawer item
I'm using below code to use navigation drawer item in my flutter app
class HomePage extends StatefulWidget {
final drawerItems = [
DrawerItem("View Your account", Icons.account_circle),
DrawerItem("Request", Icons.receipt),
DrawerItem("Order", Icons.shopping_cart),
DrawerItem("Report", Icons.report_problem),
DrawerItem("Log out", Icons.info)
];
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage> {
int _selectedDrawerIndex = 0;
bool visibilityTag = false;
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
title: Text("ORICON"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Are you sure you want to logout?"),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
"1300 898 989",
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
fontSize: 20.0),
),
),
],
),
actions: [okButton, cancelButton],
);
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return alert;
},
);
}
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
visibilityTag = false;
return AccountDetails();
case 1:
visibilityTag = true;
return RequestBin();
case 2:
visibilityTag = true;
return OrderBin();
case 3:
visibilityTag = true;
return Report();
case 4:
showAlertDialog(context);
visibilityTag = false;
return AccountDetails();
default:
return new Text("Error");
}
}
_onSelectItem(int index) {
if (index == 0) {
visibilityTag = false;
} else {
visibilityTag = true;
}
// setState(() => _selectedDrawerIndex = index);
_selectedDrawerIndex = index; // removed setState call
Navigator.of(context).pop(); // close the drawer
}
#override
Widget build(BuildContext context) {
List<Widget> drawerOptions = [];
for (var i = 0; i < widget.drawerItems.length; i++) {
var d = widget.drawerItems[i];
drawerOptions.add(new ListTile(
leading: Icon(d.icon),
title: Text(d.title),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
));
}
Future<bool> customPop() {
if (_selectedDrawerIndex == 0) {
visibilityTag = false;
return Future.value(true);
} else {
setState(() {
visibilityTag = false;
_selectedDrawerIndex = 0;
});
return Future.value(false);
}
}
void navigateToHomeScreen() {
if (_selectedDrawerIndex == 0) {
visibilityTag = false;
} else {
visibilityTag = false;
setState(() {
_selectedDrawerIndex = 0;
});
}
}
return WillPopScope(
onWillPop: customPop,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black), //add this line here
// here we display the title corresponding to the fragment
// you can instead choose to have a static title
title: Text(
widget.drawerItems[_selectedDrawerIndex].title,
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10),
child: Visibility(
visible: visibilityTag,
child: Row(
children: <Widget>[
IconButton(
icon: new Icon(Icons.arrow_back_ios),
color: Colors.grey,
onPressed: navigateToHomeScreen,
),
Text(
"BACK",
style: TextStyle(color: Colors.grey),
)
],
)),
)
],
),
drawer: Drawer(
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: new Text("Nilesh Rathod"), accountEmail: null),
Column(children: drawerOptions)
],
),
),
body: _getDrawerItemWidget(_selectedDrawerIndex)),
);
}
}
But I'm getting below Exception
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey<OverlayState>#7e1a8]
state: OverlayState#72b8b(entries: [OverlayEntry#cf40a(opaque: false; maintainState: false), OverlayEntry#e10aa(opaque: false; maintainState: true), OverlayEntry#e0ccc(opaque: false; maintainState: false), OverlayEntry#5fdab(opaque: false; maintainState: true)])
The widget which was currently being built when the offending call was made was: HomePage
dirty
dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#c84d4]]
state: HomePageState#982b0
User-created ancestor of the error-causing widget was:
MaterialApp file:///home/ctpl119/Documents/NEW_PROJECT/oricon/oricon/lib/main.dart:11:10
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3687:11)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3702:6)
#2 State.setState (package:flutter/src/widgets/framework.dart:1161:14)
#3 OverlayState.insertAll (package:flutter/src/widgets/overlay.dart:346:5)
#4 OverlayRoute.install (package:flutter/src/widgets/routes.dart:43:24)
I have already checked below Stack-overflow links
Flutter - Cannot build because the frawework is already building
Flutter - Cannot build because the frawework is already building
Flutter Error: "Widget cannot build because is already in the process of building"
Assertion on Navigator.push() caused by OverlayEntry in Flutter
Adding OverlayEntry in Flutter
setState() or markNeedsBuild() called during build flutter
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
You can copy paste run full code below
You need WidgetsBinding.instance.addPostFrameCallback
code snippet
case 4:
//showAlertDialog(context);
WidgetsBinding.instance.addPostFrameCallback((_) {
showAlertDialog(context);
});
visibilityTag = false;
return AccountDetails();
working demo
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}
class DrawerItem {
String title;
IconData icon;
DrawerItem(this.title, this.icon);
}
class HomePage extends StatefulWidget {
final drawerItems = [
DrawerItem("View Your account", Icons.account_circle),
DrawerItem("Request", Icons.receipt),
DrawerItem("Order", Icons.shopping_cart),
DrawerItem("Report", Icons.report_problem),
DrawerItem("Log out", Icons.info)
];
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage> {
int _selectedDrawerIndex = 0;
bool visibilityTag = false;
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = FlatButton(
child: Text("OK"),
onPressed: () {
Navigator.of(context).pop();
},
);
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
title: Text("ORICON"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("Are you sure you want to logout?"),
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Text(
"1300 898 989",
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
fontSize: 20.0),
),
),
],
),
actions: [okButton, cancelButton],
);
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return alert;
},
);
}
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
visibilityTag = false;
return AccountDetails();
case 1:
visibilityTag = true;
return RequestBin();
case 2:
visibilityTag = true;
return OrderBin();
case 3:
visibilityTag = true;
return Report();
case 4:
//showAlertDialog(context);
WidgetsBinding.instance.addPostFrameCallback((_) {
showAlertDialog(context);
});
visibilityTag = false;
return AccountDetails();
default:
return new Text("Error");
}
}
_onSelectItem(int index) {
if (index == 0) {
visibilityTag = false;
} else {
visibilityTag = true;
}
setState(() => _selectedDrawerIndex = index);
//_selectedDrawerIndex = index; // removed setState call
Navigator.of(context).pop(); // close the drawer
}
#override
Widget build(BuildContext context) {
List<Widget> drawerOptions = [];
for (var i = 0; i < widget.drawerItems.length; i++) {
var d = widget.drawerItems[i];
drawerOptions.add(new ListTile(
leading: Icon(d.icon),
title: Text(d.title),
selected: i == _selectedDrawerIndex,
onTap: () => _onSelectItem(i),
));
}
Future<bool> customPop() {
if (_selectedDrawerIndex == 0) {
visibilityTag = false;
return Future.value(true);
} else {
setState(() {
visibilityTag = false;
_selectedDrawerIndex = 0;
});
return Future.value(false);
}
}
void navigateToHomeScreen() {
if (_selectedDrawerIndex == 0) {
visibilityTag = false;
} else {
visibilityTag = false;
setState(() {
_selectedDrawerIndex = 0;
});
}
}
return WillPopScope(
onWillPop: customPop,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black), //add this line here
// here we display the title corresponding to the fragment
// you can instead choose to have a static title
title: Text(
widget.drawerItems[_selectedDrawerIndex].title,
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10),
child: Visibility(
visible: visibilityTag,
child: Row(
children: <Widget>[
IconButton(
icon: new Icon(Icons.arrow_back_ios),
color: Colors.grey,
onPressed: navigateToHomeScreen,
),
Text(
"BACK",
style: TextStyle(color: Colors.grey),
)
],
)),
)
],
),
drawer: Drawer(
child: Column(
children: <Widget>[
UserAccountsDrawerHeader(
accountName: new Text("Nilesh Rathod"), accountEmail: null),
Column(children: drawerOptions)
],
),
),
body: _getDrawerItemWidget(_selectedDrawerIndex)),
);
}
}
class AccountDetails extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("AccountDetails");
}
}
class RequestBin extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("RequestBin");
}
}
class OrderBin extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("OrderBin");
}
}
class Report extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text("Report");
}
}
You should make _selectedDrawerIndex a global variable (aka put it above the classes). You don't need to use setState to change the value of the variable. When you pop a route, it causes the widget to rebuild.
_onSelectItem(int index) {
if (index == 0) {
visibilityTag = false;
} else {
visibilityTag = true;
}
_selectedDrawerIndex = index; // removed setState call
Navigator.of(context).pop();
}
Also, functions like showAlertDialog(context); should not be in a setState call.
So, in summary:
Remove setState calls that change the value of _selectedDrawerIndex and showAlertDialog.
showAlertDialog has a builder so there's no reason to call setState if it's going to rebuild anyways.
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
visibilityTag = false;
return AccountDetails();
case 1:
visibilityTag = true;
return RequestBin();
case 2:
visibilityTag = true;
return OrderBin();
case 3:
visibilityTag = true;
return Report();
case 4:
setState(() {
visibilityTag = false;
});
showAlertDialog(context);
return AccountDetails();
default:
return new Text("Error");
}
}

Reading an image file from device storage and converting to Base64 results in an invalid base64 in Flutter

I'm trying to read file from a known path get base64 string from the image. I still don't understand why base64 is broken. This happens only in flutter code.
I did try doing the same conversion using a simple dart program i got the desired base64 string. This issue is happening in flutter.
onPressed: () async {
File imageFile =
await ImagePicker.pickImage(source: ImageSource.camera);
if (imageFile != null) {
Uint8List bytes = await imageFile.readAsBytes();
String base64data = base64.encode(bytes);
print(base64data);
}
}
Following is my console output.
W/ExifInterface(15331): Skip the tag entry since tag number is not defined: 2
W/ExifInterface(15331): Stop reading file since a wrong offset may cause an infinite loop: 0
I/chatty (15331): uid=10271(com.crowdanalytix.datax_app) Binder:15331_5 identical 2 lines
W/ExifInterface(15331): Stop reading file since a wrong offset may cause an infinite loop: 0
I/flutter (15331): /9j/4QGLRXhpZgAATU0AKgAAAAgACAEAAAQAAAABAAAKMgEQAAIAAAAOAAAAbgEBAAQAAAABAAASIAEPAAIAAAAIAAAAfIdpAAQAAAABAAAAmAESAAMAAAABAAAAAAEyAAIAAAAUAAAAhIglAAQAAAABAAABCgAAAABPTkVQTFVTIEEzMDAzAE9uZVBsdXMAMjAxOTowOTowMiAxOTo0MDo1MgAAB6QDAAMAAAABAAAAAIgnAAMAAAABD6AAAJIKAAUAAAABAAAA8oKaAAUAAAABAAAA+pIJAAMAAAABABAAAJIIAAQAAAABAAAAAIKdAAUAAAABAAABAgAAAAAAAAGqAAAAZAAAAkwAACcQAABOIAAAJxAAAQAFAAEAAAAHAAABHAAAAAAyMDAvMTAwAAQBEAACAAAADgAAAVkBDwACAAAACAAAAWcBEgADAAAAAQAAAAABMgACAAAAFAAAAW8AAAAAT05FUExVUyBBMzAwMwBPbmVQbHVzADIwMTk6MDk6MDIgMTk6NDA6NTIA/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgSIAoyAwEiAAIRAQMRAf/EAB8AAAIDAQEBAQEBAQAAAAAAAAQFAwYHAggAAQkKC//EAF0QAAEBBAYHCAIBAwMDAQECHwIBAAMREgQhIjFBUQUyYXGBkfAGE0KhscHR4VLxIwcUYjNDchVTgghjkhYkc4OiNJOjF0RUstIlZISzwsPilMTTGHSkNVW01PP0/8QAHAEAAwEBAQEBAQAAAAAAAAAAAgMEAAEFBgcI/8QAQhEAAAQDBgUFAQEAAQQBAgENAAECEQMhMRJBUWFx8IG
Base64 string which i'm getting is invalid. Can someone try this?
I'm using a OnePlus3t (ONEPLUS A3003).
print function did not print everything.
you can see full result with debug mode
code snippet
List<int> imageBytes = await _imageFile.readAsBytes();
String base64Image = base64Encode(imageBytes);
print(base64Image);
Copy base64 string from debug mode and paste to online converter, you can see result is correct.
full code from offical demo and add base64 convert
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_player/video_player.dart';
import 'dart:typed_data';
import 'package:image/image.dart' as ImageProcess;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File _imageFile;
dynamic _pickImageError;
bool isVideo = false;
VideoPlayerController _controller;
String _retrieveDataError;
Future<void> _playVideo(File file) async {
if (file != null && mounted) {
await _disposeVideoController();
_controller = VideoPlayerController.file(file);
await _controller.setVolume(1.0);
await _controller.initialize();
await _controller.setLooping(true);
await _controller.play();
setState(() {});
}
}
void _onImageButtonPressed(ImageSource source) async {
if (_controller != null) {
await _controller.setVolume(0.0);
}
if (isVideo) {
final File file = await ImagePicker.pickVideo(source: source);
await _playVideo(file);
} else {
try {
_imageFile = await ImagePicker.pickImage(source: source);
List<int> imageBytes = await _imageFile.readAsBytes();
String base64Image = base64Encode(imageBytes);
print(base64Image);
setState(() {});
} catch (e) {
_pickImageError = e;
}
}
}
#override
void deactivate() {
if (_controller != null) {
_controller.setVolume(0.0);
_controller.pause();
}
super.deactivate();
}
#override
void dispose() {
_disposeVideoController();
super.dispose();
}
Future<void> _disposeVideoController() async {
if (_controller != null) {
await _controller.dispose();
_controller = null;
}
}
Widget _previewVideo() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_controller == null) {
return const Text(
'You have not yet picked a video',
textAlign: TextAlign.center,
);
}
return Padding(
padding: const EdgeInsets.all(10.0),
child: AspectRatioVideo(_controller),
);
}
Widget _previewImage() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
return Image.file(_imageFile);
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
await _playVideo(response.file);
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
});
}
} else {
_retrieveDataError = response.exception.code;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Platform.isAndroid
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return isVideo ? _previewVideo() : _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: (isVideo ? _previewVideo() : _previewImage()),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'image0',
tooltip: 'Pick Image from gallery',
child: const Icon(Icons.photo_library),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'image1',
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.gallery);
},
heroTag: 'video0',
tooltip: 'Pick Video from gallery',
child: const Icon(Icons.video_library),
),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
backgroundColor: Colors.red,
onPressed: () {
isVideo = true;
_onImageButtonPressed(ImageSource.camera);
},
heroTag: 'video1',
tooltip: 'Take a Video',
child: const Icon(Icons.videocam),
),
),
],
),
);
}
Text _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError);
_retrieveDataError = null;
return result;
}
return null;
}
}
class AspectRatioVideo extends StatefulWidget {
AspectRatioVideo(this.controller);
final VideoPlayerController controller;
#override
AspectRatioVideoState createState() => AspectRatioVideoState();
}
class AspectRatioVideoState extends State<AspectRatioVideo> {
VideoPlayerController get controller => widget.controller;
bool initialized = false;
void _onVideoControllerUpdate() {
if (!mounted) {
return;
}
if (initialized != controller.value.initialized) {
initialized = controller.value.initialized;
setState(() {});
}
}
#override
void initState() {
super.initState();
controller.addListener(_onVideoControllerUpdate);
}
#override
void dispose() {
controller.removeListener(_onVideoControllerUpdate);
super.dispose();
}
#override
Widget build(BuildContext context) {
if (initialized) {
return Center(
child: AspectRatio(
aspectRatio: controller.value?.aspectRatio,
child: VideoPlayer(controller),
),
);
} else {
return Container();
}
}
}

Flutter Directory.systemTemp is not working in the release apk

I'm trying to capture an image from camera and save it in cache(i.e., Directory.systemTemp available from dart.io package). It is working fine in debug mode. But when I build the release apk and install, it is not working. This is the code:
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class CameraExampleHome extends StatefulWidget {
#override
_CameraExampleHomeState createState() {
return new _CameraExampleHomeState();
}
}
/// Returns a suitable camera icon for [direction].
IconData getCameraLensIcon(CameraLensDirection direction) {
switch (direction) {
case CameraLensDirection.back:
return Icons.camera_rear;
case CameraLensDirection.front:
return Icons.camera_front;
case CameraLensDirection.external:
return Icons.camera;
}
throw new ArgumentError('Unknown lens direction');
}
void logError(String code, String message) =>
print('Error: $code\nError Message: $message');
class _CameraExampleHomeState extends State<CameraExampleHome> {
CameraController controller;
String imagePath;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Future<List<CameraDescription>> getCameras() async {
return await availableCameras();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: const Text('Camera example'),
),
body: FutureBuilder(
future: getCameras(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return new Text('loading...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else {
if (snapshot.hasData)
return createCameraView(context, snapshot);
else
return new Text('Null');
}
}
},
),
);
}
/// Display the preview from the camera (or a message if the preview is not available).
Widget _cameraPreviewWidget() {
if (controller == null || !controller.value.isInitialized) {
return const Text(
'Tap a camera',
style: const TextStyle(
color: Colors.white,
fontSize: 24.0,
fontWeight: FontWeight.w900,
),
);
} else {
return new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller),
);
}
}
/// Display the thumbnail of the captured image or video
/// Display the control bar with buttons to take pictures and record videos.
Widget _captureControlRowWidget() {
return new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new IconButton(
icon: const Icon(Icons.camera_alt),
color: Colors.blue,
onPressed: controller != null &&
controller.value.isInitialized &&
!controller.value.isRecordingVideo
? onTakePictureButtonPressed
: null,
),
],
);
}
/// Display a row of toggle to select the camera (or a message if no camera is available).
Widget _cameraTogglesRowWidget(var cameras) {
final List<Widget> toggles = <Widget>[];
if (cameras.isEmpty) {
return const Text('No camera found');
} else {
for (CameraDescription cameraDescription in cameras) {
toggles.add(
new SizedBox(
width: 90.0,
child: new RadioListTile<CameraDescription>(
title:
new Icon(getCameraLensIcon(cameraDescription.lensDirection)),
groupValue: controller?.description,
value: cameraDescription,
onChanged: controller != null && controller.value.isRecordingVideo
? null
: onNewCameraSelected,
),
),
);
}
}
return new Row(children: toggles);
}
String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString();
void showInSnackBar(String message) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(message)));
}
void onNewCameraSelected(CameraDescription cameraDescription) async {
if (controller != null) {
await controller.dispose();
}
controller = new CameraController(cameraDescription, ResolutionPreset.high);
// If the controller is updated then update the UI.
controller.addListener(() {
if (mounted) setState(() {});
if (controller.value.hasError) {
showInSnackBar('Camera error ${controller.value.errorDescription}');
}
});
try {
await controller.initialize();
} on CameraException catch (e) {
_showCameraException(e);
}
if (mounted) {
setState(() {});
}
}
void onTakePictureButtonPressed() {
takePicture().then((String filePath) {
if (mounted) {
setState(() {
imagePath = filePath;
// videoController?.dispose();
// videoController = null;
});
if (filePath != null) showInSnackBar('Picture saved to $filePath');
}
});
}
Future<String> takePicture() async {
if (!controller.value.isInitialized) {
showInSnackBar('Error: select a camera first.');
return null;
}
//final Directory extDir = await getApplicationDocumentsDirectory();
final Directory extDir = Directory.systemTemp;
final String dirPath = '${extDir.path}/Pictures/flutter_test';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';
if (controller.value.isTakingPicture) {
// A capture is already pending, do nothing.
return null;
}
try {
await controller.takePicture(filePath);
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
return filePath;
}
void _showCameraException(CameraException e) {
logError(e.code, e.description);
showInSnackBar('Error: ${e.code}\n${e.description}');
}
Widget createCameraView(BuildContext context, AsyncSnapshot snapshot) {
return new Column(
children: <Widget>[
new Expanded(
child: new Container(
width: MediaQuery.of(context).size.width,
child: _cameraPreviewWidget(),
),
),
_captureControlRowWidget(),
new Padding(
padding: const EdgeInsets.all(5.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_cameraTogglesRowWidget(snapshot.data),
//_thumbnailWidget(),
],
),
),
],
);
}
}
class CameraApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new CameraExampleHome(),
);
}
}
List<CameraDescription> cameras;
void main() {
// Fetch the available cameras before initializing the app.
runApp(new CameraApp());
}
I've tried setting the directory to await getApplicationDocumentsDirectory() like this:
final Directory extDir = await getApplicationDocumentsDirectory();
//final Directory extDir = Directory.systemTemp;
final String dirPath = '${extDir.path}/Pictures/flutter_test';
await new Directory(dirPath).create(recursive: true);
final String filePath = '$dirPath/${timestamp()}.jpg';
Then the pictures are being saved both in debug mode and the release apk. But the pictures are lost once I relaunch the app. I want them to accessible even after the app is relaunched(that is the main reason why I want to use cache).
So what's going wrong when I try to save to cache in release build of the app?
use the path_provider package instead to get the temp path https://pub.dartlang.org/packages/path_provider
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
Directory.systemTemp is only supposed to be used on the server/console.

Categories

Resources