Handle large number of http requests at once in flutter - flutter

Requirement:
I've 1000 URLs of PDF, from which I want to create the zip.
Function:
static Future<bool> downloadZip(List<String> urls) {
int counter = 0
for(String url in urls) {
bytesForFileAtUrl(url).then((bytes){
counter++;
if(bytes != null) {
//Add bytes to the zip encoder
}
if(counter == urls.length) {
//close the zip encoder
//download the zip file
}
}
}
}
static Future<Uint8List> bytesForFileAtUrl(String url) async {
try {
http.Response response = await http.get(url);
return response?.bodyBytes;
} catch (e) {
print('Error getting bytes: ${e.toString()}');
return null;
}
}
Problem:
When there is small number of requests its working fine. But in case large number of requests I'm getting the exception: SocketException: Connection failed (OS Error: Too many open files, errno = 24) as reported here. This might because of memory issue on my mobile device, as its working fine on the web platform.
I've tried other solutions like the one using Future.wait() suggested here, but its not working and device is hanged.
Whats the best solution for this scenario ?
Worst Solution:
Using await keyword. No exception at all, but then its taking too long for the overall process to complete.
for(String url in urls) {
final bytes = await bytesForFileAtUrl(url);
...
...
}

static Future < bool > downloadZip(List < String > urls) {
int counter = 0;
urls.forEach(async() {
await bytesForFileAtUrl(url).then((bytes){
counter++;
if (bytes != null) {
//Add bytes to the zip encoder
}
if (counter == urls.length) {
//close the zip encoder
//download the zip file
}
});
});
}
static Future < Uint8List > bytesForFileAtUrl(String url) async {
try {
http.Response response = await http.get(url);
return response?.bodyBytes;
} catch (e) {
print('Error getting bytes: ${e.toString()}');
return null;
}
}
maybe try this ?

Related

how to get an extension of any URL's content in the flutter

String savename = "VID_${DateFormat("yyyyMMdd_HHmmss").format(DateTime.now())}.mp4";
String savePath = "/storage/emulated/0/Download/$savename";
try {
await Dio().download(
"https://www.youtube.com/watch?v=eW4At7ozGFQ&list=RDeW4At7ozGFQ",
savePath,
onReceiveProgress: (received, total) {
if (total != -1) {
print("${(received / total * 100).toStringAsFixed(0)}%");
}
});
print("File is saved to download folder.");
} on DioError catch (e) {
print(e.message);
}
Cannot download Youtube videos like that. The result will be a html page for that video.

Flutter Android emulator Nexus 6p API 28 and 3rd party API

These 2 methods take a global file that is set later on and send it to OCR Space API to convert and send back a OCR PDF of the file.
The code is running well, and the output value is the OCR correctly, but it is not receiving the the URL of isCreateSearchablePdf (as stated by the OCR Space API)
Is this an issue of emulator? Or is printing value wrong?
OCRSPACEAPI website: https://ocr.space/ocrapi
void fOCR(File file) async {
try {
var uri = Uri.parse('https://api.ocr.space/parse/image?');
var request = new http.MultipartRequest("POST", uri);
request.fields["apikey"] = "myApiKey";
request.fields["language"] = "ara";
request.fields["isOverlayRequired"] = "true";
request.fields["isCreateSearchablePdf"] = "true";
http.MultipartFile multipartFile = await http.MultipartFile.fromPath(
'pdf',
file.path
);
request.files.add(multipartFile);
await request.send().then((response) async {
print("Result: ${response.statusCode}");
print(value);
});
}).catchError((e) {
print(e);
});
} catch(e){
print(e);
}
}
Future selectFile() async {
final result = await FilePicker.platform.pickFiles(allowMultiple: false);
if (result == null) return;
final path = result.files.single.path!;
print(result);
print(File(path));
setState(() => file = File(path));
enabled = true;
}

API call terminate when screen gets off (or app goes background) IOS Flutter

I have a login page which starts downloading base data for the app after user enters username and password, and its a long duration operation like 2 or 3 minutes
In IOS at the middle of downloading data if screen gets off and locked, the operations terminates.
Here is the code
LoginPage part:
var repository = GlobalRestRepository();
var db = BasicDB();
List<basicModel> notDownloaded = await db.selectByLoaded(false);
for (int i = 0; i < notDownloaded.length; i++) {
await repository.getBasic(notDownloaded.elementAt(i));
}
GlobalRestRepository part:
class GlobalRestRepository {
final HttpClient http = HttpClient();
Future<void> getBasic(basicModel model) async {
String url = "${Variables.mainUrl + basicModelUrl}";
var response = await http.postExtraToken(url);
.
.
.
}
}
HttpClient part:
import 'package:http/http.dart';
...
class HttpClient {
static final HttpClient _instance = HttpClient._privateConstructor();
factory HttpClient() {
return _instance;
}
Future<dynamic> postExtraToken(String path) async {
Response response;
try {
response = await post(Uri.parse(path),
headers: {"extra": Variables.extra, "token": Variables.token});
final statusCode = response.statusCode;
if (statusCode >= 200 && statusCode < 299) {
if (response.body.isEmpty) {
return [];
} else {
return jsonDecode(utf8.decode(response.bodyBytes));
}
} else if (statusCode >= 400 && statusCode < 500) {
throw ClientErrorException();
} else if (statusCode >= 500 && statusCode < 600) {
throw ServerErrorException();
} else {
throw UnknownException();
}
} on SocketException {
throw ConnectionException();
}
}
}
Can anyone help me with this?
Using Wakelock plugin, we can solve this problem, but I don't know this is the best solution or not.
Note: This plugin works for all the platforms except linux.
Add the below code in the screen where you are initiating the api request.
#override
void didChangeDependencies() {
super.didChangeDependencies();
checkAndEnableWakeLock();
}
void checkAndEnableWakeLock() async {
bool wakeLockEnabled = await Wakelock.enabled;
if (!wakeLockEnabled) {
Wakelock.enable();
}
}
Call disable method when all the api calls are completed.
Wakelock.disable();
Using above code you can avoid screen getting off issue.

Flutter user data taking up a lot of space

My flutter app user data takes up a lot of space. I'm currently using the following code to save the user data
class FileUtil {
static Future<String> get getFilePath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
static Future<File> get getFile async {
final path = await getFilePath;
return File('$path/user.txt');
}
static Future<File> saveToFile(String data) async {
final file = await getFile;
return file.writeAsString(data);
}
static Future readFromFile() async {
try {
final file = await getFile;
String fileContents = await file.readAsString();
log(fileContents);
return json.decode(fileContents);
} catch (e) {
return "";
}
}
String formatData() {
String formattedString;
Map x = {};
x['a'] = a;
// other variables
formattedString = json.encode(x);
return formattedString;
}
void saveData() async {
try {
await saveToFile(formatData());
//print('DATA SAVED');
} catch (e) {
//print('Could not save data due to: $e');
}
}
}
Whenever the user interacts with something in the app that needs to be saved, I run saveData(). This happens quite often in my app. However, after using the app for a while, the user data can jump to a few hundred MB. I've used a JSON calculator to estimate the space of the formatData() output string and it's much less than 1MB. What should I do to minimise user data?

Flutter upload large file with progress bar. App and Web both support

I am stuck in issue with upload large file. A flutter application compiled for Web and App (Native) when file upload from app is working fine but web it hanged. how to send large file as stream request.
I am new in flutter and working on current existing app which has a feature to upload large tutorial video files and PDF files. requirement is to show the progress bar during the upload the file, currently app has I used dio but it hanged in web version and not file not upload operation going failed.
File size approximate 400MB to 700MB
Currently using following packages
dependencies:
http: ^0.12.2
dio: ^3.0.10
Could you please help me out for this issue?
I am trying to achieve with below code but some how it not working.
https://github.com/salk52/Flutter-File-Upload-Download
It's thrown an error like "Memory buffer allocation failed ", I am unable to update the version of dio or http due to other package goes disturb. somehow I have to achieve it using httpclient or dio. I could not update the version for package because it messed up other package dependency.
Sample ref. code as below:
File size approximate around 500 MB to 700MB
For ref. following code which using in code.
Dio package example:
#Dio example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#Dio example end
#httpclient example code is there any solution with progress bar in this sample code.
Future<NormalResponse> addUpdateSubjectMaterialHttp(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
var req = http.MultipartRequest(
"POST",
Uri.parse(AppConstants.addUpdateSubjectMaterial),
);
req.headers.addAll({
'Content-type': 'application/json',
'Accept': 'application/json',
});
req.fields['ObjSubMat'] = json.encode(objSubMat);
req.fields['IsDelete'] = isDelete.toString();
req.fields['ClassesId'] = AppConstants.classesId().toString();
if (objfile != null) {
req.files.add(http.MultipartFile(
"objFile", objfile.readStream, objfile.size,
filename: objfile.name));
}
var resp = await req.send();
String result = await resp.stream.bytesToString();
objRes = NormalResponse.fromJson(json.decode(result));
print(objRes.isSuccess);
print(objRes.err);
print("Here done");
} catch (err) {
print(err);
throw err;
}
return objRes;
}
#httpclient
Http package example:
#example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#example end
You must use Future, await and async which continues the task of streams in background thread while the UI of your application works smoothly.