Json Empty after parse even though status 200 - android

I am trying to parse a JSON after doing a HTTP GET request for my flutter app, however when it is parsed, the body shows as empty, this is the parsing code
urlHausParseBox() {
Future<_GoneSmishinState> fetchUrlResponse() async {
String url = myController.text;
final response = await http.post(
Uri.parse("https://urlhaus-api.abuse.ch/v1/url/"),
headers: <String, String>{
'Accept': 'application/json',
},
body: (<String, String>{
'url': url,
'query_status': query_status,
'url_status' : url_status,
//'status' : status,
//'urlStatus' : urlStatus,
}));
After this I have a check for the 200 status, and when recieved will return this to use after the fact, I printed the fields 'query_status' and 'url_status' but they came up empty so I printed what I was returning here
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
but all that is printed out is _GoneSmishinState#23f48(lifecycle state: created, no widget, not mounted)
which is not what is supposed to be returned by the HTTP GET request
The rest of my code is below
import 'dart:convert';
import 'package:validators/validators.dart';
import 'package:flutter/material.dart';
import 'package:sms/sms.dart';
import 'dart:io';
import 'dart:developer' as developer;
import 'package:http/http.dart' as http;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
String url = "https://urlhaus-api.abuse.ch/v1/urls/recent/"; //address for URL file
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key:key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: "Gone Smishin'",
home: GoneSmishin(),
);
}
}
class GoneSmishin extends StatefulWidget {
const GoneSmishin({Key? key}) : super(key: key);
State<GoneSmishin> createState() {
return _GoneSmishinState(url_status: '', query_status: '');
}
}
class _GoneSmishinState extends State<GoneSmishin> {
String message = "";
String word = "";
bool isOn = false;
final myController = TextEditingController();
#override
void dispose() {
myController.dispose();
super.dispose();
}
_GoneSmishinState({
required this.query_status,
required this.url_status,
});
final String query_status;
final String url_status;
factory _GoneSmishinState.fromJson(Map<String, dynamic> json) {
return _GoneSmishinState(
query_status: json["query_status"],
url_status: json["url_status"],
);
}
urlHausParseBox() {
Future<_GoneSmishinState> fetchUrlResponse() async {
String url = myController.text;
final response = await http.post(
Uri.parse("https://urlhaus-api.abuse.ch/v1/url/"),
headers: <String, String>{
'Accept': 'application/json',
},
body: (<String, String>{
'url': url,
'query_status': query_status,
'url_status' : url_status,
}));
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load website');
}
}
fetchUrlResponse();
if (query_status == "ok" && url_status == "online") {
const Text ('Found in URLHause Database - Probably Smishing');
print("found");
} else if (query_status == "ok" && url_status == "offline") {
const Text ('Found in URLHaus, not online');
print("found offline");
} else {
const Text ('Found Nothing');
print("not found");
print (query_status);
print (url_status);
}
_pushInput() {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (context) {
return Scaffold(
appBar: AppBar(
title: const Text ('Submit a Link')
),
body: (
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField (
controller: myController,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter your Link Text',
contentPadding: EdgeInsets.symmetric(
vertical: 40, horizontal: 20),
),
),
ElevatedButton(
onPressed: () {
urlHausParseBox();
},
child: const Text('Submit')
)
]
)
));
}
)
);
}
#override
var buttonText = 'OFF';
String textHolder = "App is Off";
changeTextON() {
setState(() {
textHolder = "App is ON";
});
isOn == true;
}
changeTextOFF() {
setState(() {
textHolder = "App is OFF";
});
isOn == false;
}
Widget build(BuildContext context) {
final ButtonStyle outlineButtonStyle = OutlinedButton.styleFrom(
primary: Colors.black87,
minimumSize: Size(200, 130),
padding: EdgeInsets.symmetric(horizontal: 200),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(300)),
),
).copyWith(
side: MaterialStateProperty.resolveWith<BorderSide>(
(Set<MaterialState> states) {
return BorderSide(
color: Theme.of(context).colorScheme.primary,
width: 1,
);
},
),
);
return Scaffold(
appBar: AppBar(
title: const Text("Gone Smishin'"),
actions: [
IconButton(
icon: const Icon(Icons.add_link),
onPressed: _pushInput,
tooltip: 'Submit a Link'
)
],
backgroundColor: Colors.red,
),
body: Column (
children: [
Container(
padding: EdgeInsets.fromLTRB(50, 50, 50, 50),
child: Text('$textHolder',
style: TextStyle(fontSize: 50)
),
),
Container(
//child: Text(result)
),
TextButton(
style: outlineButtonStyle,
onPressed: () {
changeTextON();
},
child: Text('ON')
),
TextButton(
style: outlineButtonStyle,
onPressed: () {
changeTextOFF();
},
child: Text("OFF"),
)
]
),
);
}
}

Change this:
_GoneSmishinState({
required this.query_status,
required this.url_status,
});
final String query_status;
final String url_status;
factory _GoneSmishinState.fromJson(Map<String, dynamic> json) {
return _GoneSmishinState(
query_status: json["query_status"],
url_status: json["url_status"],
);
}
to this:
_GoneSmishinState();
var queryStatus = '';
var urlStatus = '';
and this:
if (response.statusCode == 200) {
print (_GoneSmishinState.fromJson(jsonDecode(response.body)));
return _GoneSmishinState.fromJson(jsonDecode(response.body));
}
to:
if (response.statusCode == 200) {
setState(() {
final decoded = json.decode(response.body);
queryStatus = decoded['query_status'];
urlStatus = decoded['url_status'];
}
);
}
And, finally, patch up any unused/misnamed variables. As an aside, it's difficult to read functions declared inside other functions. Is fetchUrlResponse inside urlHausParseBox? Move it outside.

Related

Flutter: TCP socket connection fails on real device

I'm posting this even though I already solved the issue, because I spent more than an hour trying to figure out what was causing it, and might help someone else.
I have a simple application that connects to a server through a TCP socket. It works fine inside the debugger with the device emulator, but when I deploy it on a real device it fails to connect immediately.
Further investigations led me to finding out that the socket was actually throwing the following exception:
SocketException: Connection failed (OS Error: Operation not permitted, errno = 1), address = 192.168.1.46, port = 40001
Code sample
Connect button opens a socket on _host:_port
Send Radar Distance button sends a message formatted like {"distance": _distance, "angle": _angle} on the socket.
Status and Message fields show info about the socket status and eventually useful infos.
main.dart
import 'package:flutter/material.dart';
import 'views/view_test.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 ViewTest(),
);
}
}
views/view_test.dart
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
const List<String> materialTypes = <String>['PLASTIC', 'GLASS'];
class ViewTest extends StatefulWidget {
const ViewTest({Key? key}) : super(key: key);
#override
State<ViewTest> createState() => _ViewTestState();
}
class _ViewTestState extends State<ViewTest> {
String _distance = "";
String _angle = "";
String _status = "";
String _message = "";
Socket? _socket;
final String _host = "192.168.1.46";
final int _port = 4001;
Future<void> _sendMessage(String message) async {
print("Sent message $message");
_socket!.write(message);
await Future.delayed(const Duration(seconds: 1));
}
void _connect(String ip, int port) async {
Socket? sock;
try {
sock =
await Socket.connect(ip, port, timeout: const Duration(seconds: 3));
_socket = sock;
setState(() {
_status = "Connected to $ip:$port.";
_message = "";
});
// listen for responses from the server
_socket!.listen(
// handle data from the server
(Uint8List data) {
final serverResponse = String.fromCharCodes(data);
setState(() {
_message = serverResponse;
});
print(serverResponse);
},
// handle errors
onError: (error) {
setState(() {
_status = "Disconnected.";
_message = "Error: $error";
});
print("Error: $error");
_socket!.destroy();
_socket = null;
},
// handle server ending connection
onDone: () {
setState(() {
_status = "Disconnected.";
_message = 'Server left.';
});
print('Server left.');
_socket!.destroy();
_socket = null;
},
);
} catch (e) {
setState(() {
_status = "Connection failed.";
_message = e.toString();
});
print("Error: ${e.toString()}");
}
}
void _disconnect() {
if (_socket != null) _socket!.destroy();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Center(child: Text("Radar Test")),
),
body: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
setState(() {
_status = "";
_message = "";
});
_disconnect();
_connect(_host, _port);
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_socket == null ? 'Connect' : 'Reconnect',
style: const TextStyle(fontSize: 22.0),
),
),
),
const SizedBox(height: 50.0),
TextField(
onChanged: (text) {
_distance = text;
},
keyboardType:
const TextInputType.numberWithOptions(decimal: false),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'[0-9]+'), // this regex allows only decimal numbers
)
],
decoration: const InputDecoration(
hintText: '100',
border: UnderlineInputBorder(),
labelText: 'Distance',
),
),
TextField(
onChanged: (text) {
_angle = text;
},
keyboardType:
const TextInputType.numberWithOptions(decimal: false),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(
RegExp(r'[0-9]+'), // this regex allows only decimal numbers
)
],
decoration: const InputDecoration(
hintText: '90',
border: UnderlineInputBorder(),
labelText: 'Angle',
),
),
const SizedBox(height: 50.0),
Text("Status: $_status"),
Text("Message: $_message"),
],
),
),
),
floatingActionButton: ElevatedButton(
onPressed: _socket == null
? null
: () {
// test
_sendMessage(
'{"distance": ${_distance.isEmpty ? 100 : int.parse(_distance)}, "angle": ${_angle.isEmpty ? 90 : int.parse(_angle)}}');
},
child: const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Send Radar Distance',
style: TextStyle(fontSize: 22.0),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
Turns out I had to give the application Internet permissions, as stated in Flutter docs about Networking. So I added the following line to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
NB: AndroidManifest.xml manifest is located in the following location:
android > app > src > main > AndroidManifest.xml

Getting null values in View Flutter

I want to get data of inventory but not getting. I am doing API integration without model because there are some issues in Model just to get data and want to display in to my view.
this is my service class of get data through API.
Future<dynamic> getInventory() async {
var data;
String? userId = await preferenceService.getuserId();
String? accessToken = await preferenceService.getAccessToken();
var response = await http.get(Uri.parse('${AppUrl.getInventory}/$userId'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Barear $accessToken'
});
print("The data of the specific inventory ===========>>>>>>>> " +
response.body.toString());
if (response.statusCode == 200) {
data = jsonDecode(response.body);
print('This is futr dsta --->>> $data');
} else {
data=[];
}
return data;
}
This is my controller class where i am using above service function
Future getMyInvenoryFromService() async {
try {
isLoadingInventory(true);
await inventoryService.getInventory().then((val) {
if (val != []) {
inventoryData = val;
} else {
inventoryData = [];
}
});
} finally {
isLoadingInventory(false);
}
}
But when i am accessing the data with inventoryData (in controller) i am getting null, but in controller i am getting values when debugging. but i am not understanding why i am receiving null values in view.
This is my view,
class _UserInventoryScreenState extends State<UserInventoryScreen> {
InventoryController inventoryController = Get.put(InventoryController());
InventoryService inventoryService = InventoryService();
GiftController giftController = Get.put(GiftController());
GiftStorageService giftStorageService = GiftStorageService();
#override
void initState() {
super.initState();
/*Future delay() async {
await new Future.delayed(new Duration(milliseconds: 3000), () {
inventoryController.getMyInvenoryFromService();
});
}*/
Timer.run(() {
inventoryController.getMyInvenoryFromService();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.pinkAppBar,
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: InkWell(
onTap: () {
Get.back();
},
child: Icon(Icons.arrow_back)),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Inventory'),
InkWell(
onTap: () {
Get.to(AddInventoryScreen());
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration:
BoxDecoration(border: Border.all(color: Colors.white)),
child: Text(
"Add Inventory",
style: TextStyle(fontSize: 16),
),
),
)
],
),
),
body: Obx(() {
return inventoryController.isLoadingInventory.value == true
? Center(child: CircularProgressIndicator())
: ElevatedButton(
onPressed: () async {
await inventoryController.getMyInvenoryFromService();
},
child: Text("${inventoryController.inventoryData.length}"),
);
If your response.statusCode isn't 200 it might be because you are setting wrong your headers:
'Authorization': 'Barear $accessToken'
Change it to:
'Authorization': 'Bearer $accessToken'

I want to get the video size from internet path for my flutter app

I'm trying to get the video file size and use it as a percent inside LinearPercentIndicator.
based on my search I found a code but for android how can I do like that on flutter.
final URL uri=new URL("http://your_url.com/file.mp4");
URLConnection connection;
try
{
connection=uri.openConnection();
connection.connect();
final String contentLengthStr=ucon.getHeaderField("content-length");
// do whatever
}
catch(final IOException exception)
{
}
PS: I'm using FFmpeg for downloading.
For instance, using dio plugin
dio using large size file downloader
url link : https://pub.dev/packages/dio
for Example
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
class LargeFileMain extends StatefulWidget {
#override
State<StatefulWidget> createState() => _LargeFileMain();
}
class _LargeFileMain extends State<LargeFileMain> {
final imgUrl =
'http://your_url.com/file.mp4';
bool downloading = false;
var progressString = "";
var file;
Future<void> downloadFile() async {
Dio dio = Dio();
try {
var dir = await getApplicationDocumentsDirectory();
await dio.download(imgUrl, '${dir.path}/myimage.jpg',
onReceiveProgress: (rec, total) {
print('Rec: $rec , Total: $total');
file = '${dir.path}/myimage.jpg';
setState(() {
downloading = true;
progressString = ((rec / total) * 100).toStringAsFixed(0) + '%';
});
});
} catch (e) {
print(e);
}
setState(() {
downloading = false;
progressString = 'Completed';
});
print('Download completed');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Large File Example'),
),
body: Center(
child: downloading
? Container(
height: 120.0,
width: 200.0,
child: Card(
color: Colors.black,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
SizedBox(
height: 20.0,
),
Text(
'Downloading File: $progressString',
style: TextStyle(
color: Colors.white,
),
)
],
),
),
)
: FutureBuilder(
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
print('none');
return Text('No Data');
case ConnectionState.waiting:
print('waiting');
return CircularProgressIndicator();
case ConnectionState.active:
print('active');
return CircularProgressIndicator();
case ConnectionState.done:
print('done');
if (snapshot.hasData) {
return snapshot.data;
}
}
return Text('No Data');
},
future: downloadWidget(file),
)),
floatingActionButton: FloatingActionButton(
onPressed: () {
downloadFile();
},
child: Icon(Icons.file_download),
),
);
}
Future<Widget> downloadWidget(String filePath) async {
File file = File(filePath);
bool exist = await file.exists();
if (exist) {
return Center(
// your video file using widget
);
} else {
return Text('No Data');
}
}
}

How to Make Customize Error Page in Webview Flutter

I am new to flutter. Currently i am building the web app that using flutter webview plugin but i have a question about the internet connectivity. When users doesnt have a connection that app gives a default error page like
Webpage not available
The webpage at https://covid19.who.int/ could be not be loaded because:
net:::ERR_Internet_disconnected
How to use custom code to show custom error page like to hide url? My proper code is:
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:covidwho/layout/myAppBar.dart';
class Who extends StatefulWidget {
#override
_WhoState createState() => _WhoState();
}
class _WhoState extends State<Who> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(),
body: Container(
child: WebviewScaffold(
url: "https://covid19.who.int/",
withJavascript: true,
withLocalStorage: true,
hidden: true,
initialChild: Container(
color: Colors.white,
child: const Center(
child: CircularProgressIndicator(
backgroundColor: Colors.black,
),
)),
),
),
);
}
}
I would like to share with you the code I use to show custom pages at the time of flutter web errors.
Full project link https://github.com/K3rimoff/flutter-custom-web-error-page
import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import '../../components/back_pressed.dart';
import '../../theme/colors.dart';
import '../error/error.dart';
class WebScreen extends StatefulWidget {
const WebScreen({super.key});
#override
State<WebScreen> createState() => _WebScreenState();
}
class _WebScreenState extends State<WebScreen> with TickerProviderStateMixin {
late AnimationController _animationController;
InAppWebViewController? _webViewController;
PullToRefreshController? _refreshController;
bool _isLoading = false, _isVisible = false, _isOffline = false;
// 0 - Everything is ok, 1 - http or other error fixed
int _errorCode = 0;
final BackPressed _backPressed = BackPressed();
Future<void> checkError() async {
//Hide CircularProgressIndicator
_isLoading = false;
//Check Network Status
ConnectivityResult result = await Connectivity().checkConnectivity();
//if Online: hide offline page and show web page
if (result != ConnectivityResult.none) {
if (_isOffline == true) {
_isVisible = false; //Hide Offline Page
_isOffline = false; //set Page type to error
}
}
//If Offline: hide web page show offline page
else {
_errorCode = 0;
_isOffline = true; //Set Page type to offline
_isVisible = true; //Show offline page
}
// If error is fixed: hide error page and show web page
if (_errorCode == 1) _isVisible = false;
setState(() {});
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: const Duration(seconds: 2));
_animationController.repeat();
_refreshController = PullToRefreshController(
onRefresh: () => _webViewController!.reload(),
options: PullToRefreshOptions(
color: Colors.white, backgroundColor: Colors.black87),
);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
child: Scaffold(
body: SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
InAppWebView(
onWebViewCreated: (controller) =>
_webViewController = controller,
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
supportZoom: false,
)),
initialUrlRequest: URLRequest(
url: Uri.parse(
"https://google.com")), // For http error: change to wrong url : https://google.com/404/
pullToRefreshController: _refreshController,
onLoadStart: (controller, url) {
setState(() {
_isLoading = true; //Show CircularProgressIndicator
});
},
onLoadStop: (controller, url) {
_refreshController!.endRefreshing();
checkError(); //Check Error type: offline or other error
},
onLoadError: (controller, url, code, message) {
// Show
_errorCode = code;
_isVisible = true;
},
onLoadHttpError: (controller, url, statusCode, description) {
_errorCode = statusCode;
_isVisible = true;
},
),
//Error Page
Visibility(
visible: _isVisible,
child: ErrorScreen(
isOffline: _isOffline,
onPressed: () {
_webViewController!.reload();
if (_errorCode != 0) {
_errorCode = 1;
}
}),
),
//CircularProgressIndicator
Visibility(
visible: _isLoading,
child: CircularProgressIndicator.adaptive(
valueColor: _animationController.drive(
ColorTween(
begin: circularProgressBegin,
end: circularProgressEnd),
),
),
),
],
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton.icon(
onPressed: () {
_errorCode = 1;//My Error fixed code
_webViewController!.loadUrl(
urlRequest: URLRequest(
url: Uri.parse("https://google.com/"), //Correct url
),
);
},
label: const Text("Load Correct URL"),
icon: const Icon(Icons.check),
),
ElevatedButton.icon(
onPressed: () {
_webViewController!.loadUrl(
urlRequest: URLRequest(
url: Uri.parse("https://google.com/404"), //Wrong url
),
);
},
label: const Text("Load Wrong URL"),
icon: const Icon(Icons.close),
),
],
),
),
onWillPop: () async {
//If website can go back page
if (await _webViewController!.canGoBack()) {
await _webViewController!.goBack();
return false;
} else {
//Double pressed to exit app
return _backPressed.exit(context);
}
});
}
}
For that you need to implement
Stream<String> onError webview event.
Don't forget to dispose webview flutterWebviewPlugin.dispose()
Here is a code sample
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
String selectedUrl = 'https://flutter.io';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Instance of WebView plugin
final flutterWebViewPlugin = FlutterWebviewPlugin();
// On destroy stream
StreamSubscription _onDestroy;
// On Http error
StreamSubscription<WebViewHttpError> _onHttpError;
final _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
flutterWebViewPlugin.launch(selectedUrl);
// Add a listener to on destroy WebView, so you can make came actions.
_onDestroy = flutterWebViewPlugin.onDestroy.listen((_) {
if (mounted) {
// Actions like show a info toast.
_scaffoldKey.currentState.showSnackBar(
const SnackBar(content: const Text('Webview Destroyed')));
}
});
_onHttpError =
flutterWebViewPlugin.onHttpError.listen((WebViewHttpError error) {
if (mounted) {
//do your customization here
}
});
}
#override
void dispose() {
// Every listener should be canceled, the same should be done with this stream.
_onDestroy.cancel();
_onHttpError.cancel();
flutterWebViewPlugin.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
);
}
}

Image_picker throws removeInvalidNode all the node in jank list is out of time instead of returning image

I am trying to choose image with gallery or camera and display with image_picker.
When I run the app in android, I am able to choose image but not displaying. In contrast I am getting following in the console for the first time.
I/HwViewRootImpl(11213): removeInvalidNode all the node in jank list is out of time
If I repeat the same, it gives following in each time while press the button instead of opening gallery or camera.
I/flutter (11213): PlatformException(already_active, Image picker is already active, null)
I found following solutions from my search but not solved my case.
flutter clean , flutter clean
changing the version of the plugin
updating all dependencies
using retrieveLostData method as stated in the plugin documentation
Following is the code I have used for retrieve image:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class CameraApp extends StatefulWidget {
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
File imageFile;
#override
void initState() {
super.initState();
}
Future _getImage(int type) async {
print("Called Image Picker");
var image = await ImagePicker.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
print("$image.path");
imageFile = image;
});
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file;
}
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Image Editor"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
imageFile != null
? Image.file(
imageFile,
height: MediaQuery.of(context).size.height / 2,
)
: Text("Image editor"),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Add Slip"),
content: Row(
children: <Widget>[
Expanded(
child: new FlatButton(
child: new Text("Camera"),
onPressed: () {
_getImage(1);
Navigator.pop(context);
},
),
),
Expanded(
child: new FlatButton(
child: new Text("Gallery"),
onPressed: () {
_getImage(2);
Navigator.pop(context);
},
),
)
],
),
);
},
);
},
tooltip: 'Pick Image',
child: Icon(Icons.camera),
),
);
}
}
I've tried the sample code that you've shared and for some reason got compiler issues but not the same issue as yours. Therefore, I've tried to debug your code. Here is the fixed code:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.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: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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;
#override
void initState() {
super.initState();
}
Future _getImage(int type) async {
print("Called Image Picker");
var image = await await ImagePicker.platform.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
print("$image.path");
imageFile = File(image.path);
});
}
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.platform.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file as File;
}
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Image Editor"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
imageFile != null
? Image.file(
imageFile,
height: MediaQuery.of(context).size.height / 2,
)
: Text("Image editor"),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Add Slip"),
content: Row(
children: <Widget>[
Expanded(
child: new FlatButton(
child: new Text("Camera"),
onPressed: () {
_getImage(1);
Navigator.pop(context);
},
),
),
Expanded(
child: new FlatButton(
child: new Text("Gallery"),
onPressed: () {
_getImage(2);
Navigator.pop(context);
},
),
)
],
),
);
},
);
},
tooltip: 'Pick Image',
child: Icon(Icons.camera),
),
);
}
}
Few of the fixes are these lines:
var image = await await ImagePicker.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
It's having an error in the compiler so I've changed it to this:
var image = await await ImagePicker.platform.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
Same to these lines:
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response;
}
});
}
}
Fixed version:
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.platform.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file as File;
}
});
}
}
and this
setState(() {
print("$image.path");
imageFile = image;
}
to this:
setState(() {
print("$image.path");
imageFile = File(image.path);
}
The reason could be the version of image_picker that I'm using. Currently I'm using the image_picker: ^0.7.4.
Here is actual output:
I've also encounter an issue if your running this in an Android API version 30, you get this error:
Unhandled Exception: PlatformException(no_available_camera, No cameras available for taking pictures., null, null)
The workaround is to add <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> in manifest as mentioned in this GitHub post.

Categories

Resources