I'm using the flutter_downloader package to download files with my app.
The progress notification is working nicely. but my ReceivePort is not listening to the progress.
final ReceivePort port = ReceivePort();
#override
void initState() {
super.initState();
IsolateNameServer.registerPortWithName(
port.sendPort, 'downloader_sendport');
port.listen((dynamic data) async {
log('data: $data'); // don't work
});
FlutterDownloader.registerCallback(downloadCallback);
}
#pragma('vm:entry-point')
static void downloadCallback(
String id, DownloadTaskStatus status, int progress) {
log("downloadCallback => $id, $status, $progress"); // works
final SendPort? send =
IsolateNameServer.lookupPortByName('downloader_sendport');
send?.send([id, status, progress]);
}
change status to primitive value in send method
The problem was with sending DownloadTaskStatus:
solution:
send?.send([id, status.value, progress]);
Related
I'm trying to use Flutter_downloader to make my app able to download some attachment file and it work just fine. So I make the Isolate into class to tidy things up and tried to use the progress so I can show the download progress in my UI but the progress stays at 0.
How to fix this ? The download work just fine.
Flutter Downloader Isolate Code:
class DownloaderIsolate {
//Callback for the Flutter_Downloader
static downloadCallback(String id, DownloadTaskStatus status, int progress) {
final SendPort send =
IsolateNameServer.lookupPortByName('downloader_send_port')!;
send.send([id, status, progress]);
}
static setupDownloaderPort({int? progress}) {
ReceivePort _port = ReceivePort();
IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
FlutterDownloader.registerCallback(DownloaderIsolate.downloadCallback);
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
progress = data[2];
});
}
}
My UI Page Code:
int? progress = 0;
void initState(){
DownloaderIsolate.setupDownloaderPort(progress: progress);
}
Widget build(BuildContext context) {
//Some Parents Code
//Trying to show the progress in String
Text(progress.toString()),
//Also Trying to show the progress
Text('$progress'),
}
The problem might be that you need to "setState" in order for your UI to update, but you can't setState in your isolate class. You can try the following:
Flutter Downloader Isolate Code:
static setupDownloaderPort({required Function(int) updateProgress}) {
ReceivePort _port = ReceivePort();
IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
FlutterDownloader.registerCallback(DownloaderIsolate.downloadCallback);
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
updateProgress(data[2]);
});
}
UI Page:
int? progress = 0;
void initState(){
DownloaderIsolate.setupDownloaderPort(updateProgress: (_p) {
progress = _p;
});
super.initState();
}
Widget build(BuildContext context) {
//Some Parents Code
//Trying to show the progress in String
Text(progress.toString()),
//Also Trying to show the progress
Text('$progress'),
}
Future<void> setEmpId(String empId) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(this.empId, empId);
}
Future<String> getEmpId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String empId;
empId = await prefs.getString(this.empId) ?? '';
return empId;
}
Prefs().setEmpId(state.empVerifyEntity.employee.empId);//set empId from api
In Another Class:
class Page extends State<Page>{
Future<void> getEmpId() async {
String empId = await Prefs().getEmpId().toString();
print("----------->>>>>>>>$empId");
}
#override
void initState() {
super.initState();
getEmpId();
}
}
Here I'm getting instance of future, I tried every method like .then(value) Each and every method I'm getting instance of future. how to data correctly?
The problem you have is due to the fact that your initState method is synchronous and the method in which you are getting the value for EmpId isn't.
Therefore, it is not waiting for the result of the call.
You can accomplish this in several ways:
Add a then clause to the call of getEmpId
#override
void initState() {
super.initState();
getEmpId().then((result) {
//your logic here
)
}
Add a PostFrameCallback
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
getEmpId();
});
}
below is my websocket provider .it doesn't even hit to the server when I called from block builder
I can connect to the server without bloc, I tried a lot examples but failed
I need help guys , thanks
any example about flutter bloc with web_socket_channel
WebSocket provider
static final String wsRelationUrl = "ws://127.0.0.1:8080/chat/";
final IOWebSocketChannel _channel =
IOWebSocketChannel.connect(wsRelationUrl, headers: headers);
WebSocketProvider();
#override
Future<void> disconect() async {
if (_channel != null) {
_channel.sink.close();
}
}
#override
Future<Stream> messages() async {
if (_channel != null) {
return _channel.stream;
}
return null;
}
#override
Future<void> sendMessage(String message) async {
if (_channel != null) {
return _channel.sink.add(message);
}
}
}
I am creating an app and I use signalr, I am able to connect to the hub, but it is not possible to invoke a method, every time I get this exception:Unhandled Exception: type 'GeneralError' is not a subtype of type 'Error' in type cast
Here my code:
var hubConnection;
String mobileSession;
Future<void> createSignalRConnection() async {
hubConnection =
new HubConnectionBuilder().withUrl(GLOBAL_BACKEND_SESSION_NEW).build();
await hubConnection.start();
logger.log(Level.INFO, "Connection successful");
hubConnection.onclose((error) {
logger.log(Level.INFO, "Connection Closed");
createSignalRConnection();
});
}
Future<bool> sendParingCode(String pairingCode) async {
final result = await hubConnection
.invoke("RequestPairing", args: [mobileSession, pairingCode]);
logger.log(Level.INFO, "Pairing successful");
return true;
}
void initSession() async {
mobileSession = await hubConnection
.invoke("InitSession");
print(mobileSession);
logger.log(Level.INFO, "Session init successful");
}
I use it like this in a PageState:
void initState() {
super.initState();
createSignalRConnection();
initSession();
}
I think you should wait for createSignalRConnection to be completed before calling invoke method. Try this:
#override
void initState() {
super.initState();
_asyncInitState();
}
Future<void> _asyncInitState() async {
await createSignalRConnection(); // HERE: add await
initSession();
}
I have order which have 4 status : preparing , pending , delivering and delivered. and when the order status changed from one to another I wanted to show a notification to the user of the change occurs.
*I have used local notifications plugin. In order page widget shown here it is triggered by a stream above that get the order from fire-base.
*That's why I supposed that each time the status will change the orderPage will be rebuild again and initstate will be recalled and send the new notification msg with new status, but that didn't happen.
Another solution was to use didchangedependency but I got no different result.
This was a missed work I know, but this is what came to my mind.
*What I exactly want is something that make me listen on the status and when changes occur a function " singleNotification" will be called to show the notification.
any Help will be appreciated.
class OrderPage extends StatefulWidget {
const OrderPage({
Key key,
#required this.order,
}) : super(key: key);
final Order order;
#override
OrderPageState createState() {
return new OrderPageState();
}
}
class OrderPageState extends State<OrderPage> {
final DateTime now = DateTime.now().toUtc().add(
Duration(seconds: 3),
);
String title = "notification";
String msg = "";
FlutterLocalNotificationsPlugin localNotificationsPlugin =
FlutterLocalNotificationsPlugin();
initializeNotifications() async {
var initializeAndroid =
AndroidInitializationSettings('#mipmap/ic_launcher');
var initializeIOS = IOSInitializationSettings();
var initSettings = InitializationSettings(initializeAndroid, initializeIOS);
await localNotificationsPlugin.initialize(initSettings);
}
Future singleNotification(
DateTime datetime, String message, String subtext, int hashcode,
{String sound}) async {
var androidChannel = AndroidNotificationDetails(
'channel-id',
'channel-name',
'channel-description',
importance: Importance.Max,
priority: Priority.Max,
);
var iosChannel = IOSNotificationDetails();
var platformChannel = NotificationDetails(androidChannel, iosChannel);
localNotificationsPlugin.schedule(
hashcode, message, subtext, datetime, platformChannel,
payload: hashcode.toString());
}
#override
void initState() {
super.initState();
getMsgState(widget.order.status);
initializeNotifications();
singleNotification(
now,
title,
msg,
98123871,
);
}
#override
void didChangeDependencies() {
super.didChangeDependencies();
getMsgState(widget.order.status);
initializeNotifications();
singleNotification(
now,
title,
msg,
98123871,
);
}
Widget build(BuildContext context) {
return Container();
}
String getMsgState(String orderStatus) {
switch (orderStatus) {
case 'pending':
return msg = "Your order is pending";
break;
case 'preparing':
return msg = "your order is currently preparing";
break;
case 'delivering':
return msg = "your order is currently delivering";
break;
case 'delivered':
return msg = "Your order is delivered";
default:
return msg = "CustomStepState.Complete";
break;
}
}
If I understand correctly, Firebase knows when the order status is changed. And it sends a notification. And you would like to show it to the user.
You can use FCM and Firebase in-app notification. One of my project had a similar requirement whether server does the processing and the Flutter mobile app shows the status. I did the following :
Wrote a small code on the server side which calls Firebase cloud message API with user display message and data payload.
Wrote a code on Flutter mobile app side to display the notification (in the in-app style) if the app is already in the foreground.
Sample code snippet :
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
Helper.write('on message $message');
//Map data = json.decode(message);
this.scaffoldKey.currentState.showSnackBar(SnackBar(content: Text(message['aps']['alert']['body']),));
},
onResume: (Map<String, dynamic> message) async {
Helper.write('on resume $message');
},
onLaunch: (Map<String, dynamic> message) async {
Helper.write('on launch $message');
},
);
analytics.logEvent(name:'firebaseCloudMessaging_Listeners_Done',parameters:null);
}