dart Isolate listen don't triggered (or work) - flutter

My class:
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter_downloader/flutter_downloader.dart';
class SettingsPage extends StatefulWidget with WidgetsBindingObserver {
SettingsPage({Key? key}) : super(key: key);
#override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
final ReceivePort _port = ReceivePort();
int uploadProgress = 0;
// (-1)
DownloadTaskStatus uploadStatus = DownloadTaskStatus(-1);
String identifier = '';
get downloadsPath =>
storage.read('downloadsPath') ?? AndroidPathProvider.downloadsPath;
#override
void initState() {
super.initState();
_bindBackgroundIsolate();
FlutterDownloader.registerCallback(downloadCallback);
}
#override
void dispose() {
_unbindBackgroundIsolate();
super.dispose();
}
void _bindBackgroundIsolate() {
final isSuccess = IsolateNameServer.registerPortWithName(
_port.sendPort, 'downloader_send_port');
simplelog.i('regPort: $isSuccess');
if (!isSuccess) {
_unbindBackgroundIsolate();
_bindBackgroundIsolate();
return;
}
///Listening for the data is comming other isolataes
simplelog.i('before listen');
_port.listen((dynamic data) {
simplelog.i('in listen');
final String _id = data[0];
final DownloadTaskStatus _status = data[1];
final int _progress = data[2];
simplelog.i(
'Callback on UI isolate: '
'task ($_id) is in status ($_status) and process ($_progress)',
);
setState(() {
uploadProgress = _progress;
uploadStatus = _status;
simplelog.i('inside setState');
});
simplelog.i(
'uploadProgress = $uploadProgress \n uploadStatus = $uploadStatus \n uploadStatus.value = ${uploadStatus.value}');
if (uploadProgress == 100 &&
uploadStatus == DownloadTaskStatus.complete &&
uploadStatus.value == 3) {
try {
OpenFilex.open('$downloadsPath/${Consts.apkName}');
} catch (e) {
simplelog.e('Cannot open file ${Consts.apkName}! \n $e');
}
}
}, onError: (err) {
simplelog.e('ISOLATE LISTEN ERROR: $err');
},
onDone: () {
simplelog.i('onDone listen');
});
}
void _unbindBackgroundIsolate() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
}
#pragma('vm:entry-point')
static void downloadCallback(
String id,
DownloadTaskStatus status,
int progress,
) {
simplelog.i('Callback on background isolate: '
'task ($id) is in status ($status) and progress ($progress)');
IsolateNameServer.lookupPortByName('downloader_send_port')
?.send([id, status, progress]);
}
In case with dowloadCallback all work good,
but in case _port.listen(), I don't get any data (simplelog = print, it nothing to show me, work only case simplelog.i('before listen');
In init() method register callback, this prints works good, and file success downloaded
How I can solve this problem?
Tried to play around with opening and closing ports using Compiler

Related

How to write and read data anywhere by shared_preferences on Flutter 3.7 background isolates?

On Flutter 3.7 platform channels can run on any isolate. So I tried this sample,
import ‘package:flutter/services.dart’;
import ‘package:shared_preferences/shared_preferences.dart’;
void main() {
// Identify the root isolate to pass to the background isolate.
// (API introduced in Flutter 3.7)
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
Isolate.spawn(_isolateMain, rootIsolateToken);
}
void _isolateMain(RootIsolateToken rootIsolateToken) async {
// Register the background isolate with the root isolate.
BackgroundIsolateBinaryMessenger
.ensureInitialized(rootIsolateToken);
// You can now use the shared_preferences plugin.
SharedPreferences sharedPreferences =
await SharedPreferences.getInstance();
print(sharedPreferences.getBool(‘isDebug’));
}
I can read from data on shared_preferences in this sample okey. But how can I use this feature anywhere in my app? How can I set or read data using this isolate on initState for example?
Basically you need to implement communication between isolates. You can read more about it here
Here is an example, you can change flutter_secure_storage that i used with shared_preferences package
import 'dart:async';
import 'dart:isolate';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class CreationEvent {
final RootIsolateToken isolateToken;
final SendPort sendPort;
CreationEvent(this.isolateToken, this.sendPort);
}
class DeletetionEvent {}
class ReadEvent {
final String key;
const ReadEvent(this.key);
}
class ReadResult {
final String key;
final String? content;
const ReadResult(this.key, this.content);
}
class IsolateIO {
IsolateIO._();
final _toBgPort = Completer();
final Map<Object, Completer> _completerMap = {};
Isolate? _isolate;
StreamSubscription? _fromBgListener;
void start() async {
RootIsolateToken rootIsolateToken = RootIsolateToken.instance!;
ReceivePort fromBG = ReceivePort();
_fromBgListener = fromBG.listen((message) {
// setup process
if (message is SendPort) {
_toBgPort.complete(message);
return;
}
if (message is ReadResult) {
_completerMap['read:${message.key}']?.complete(message.content);
_completerMap.remove('read:${message.key}');
}
});
_isolate = await Isolate.spawn(
(CreationEvent data) {
final worker = IsolateWorker(data.isolateToken, data.sendPort);
worker.listen();
},
CreationEvent(rootIsolateToken, fromBG.sendPort),
);
}
Future<String?> readFromStorage(String key) async {
// make sure isolate created with ports
final port = await _toBgPort.future;
// store completer
final completer = Completer<String?>();
_completerMap['read:$key'] = completer;
// send key to be read
port.send(ReadEvent(key));
// return result
return completer.future;
}
void stop() async {
if (_toBgPort.isCompleted) {
final port = await _toBgPort.future;
port.send(DeletetionEvent());
}
_fromBgListener?.cancel();
_isolate?.kill(priority: Isolate.immediate);
}
static final i = IsolateIO._();
}
class IsolateWorker {
final RootIsolateToken rootIsolateToken;
final SendPort toMain;
final FlutterSecureStorage storage;
StreamSubscription? subs;
IsolateWorker(
this.rootIsolateToken,
this.toMain, {
this.storage = const FlutterSecureStorage(
aOptions: AndroidOptions(
encryptedSharedPreferences: true,
),
),
}) {
// Register the background isolate with the root isolate.
BackgroundIsolateBinaryMessenger.ensureInitialized(rootIsolateToken);
}
void listen() {
ReceivePort fromMain = ReceivePort();
toMain.send(fromMain.sendPort);
subs = fromMain.listen((message) => onMessage(message));
}
void onMessage(dynamic message) async {
if (message is DeletetionEvent) {
subs?.cancel();
return;
}
if (message is ReadEvent) {
final rawJson = await storage.read(key: message.key);
toMain.send(ReadResult(message.key, rawJson));
}
}
}
class View extends StatefulWidget {
const View({super.key});
#override
State<View> createState() => _ViewState();
}
class _ViewState extends State<View> {
String username = '';
#override
void initState() {
super.initState();
IsolateIO.i.start();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final name = await IsolateIO.i.readFromStorage('username');
setState(() {
username = name ?? '';
});
});
}
#override
void dispose() {
IsolateIO.i.stop();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SizedBox(
child: Text(username),
);
}
}

"The named parameter 'channelId' is required, but there's no corresponding argument." Flutter error how to solve?

I tried to built video call using agora 5. But "RtcRemoteView.SurfaceView" show some error.I couldn't understand what's the reason for this.
error
imports
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
code
class VideoCall extends StatefulWidget {
final String channelName;
final ClientRole role;
const VideoCall({Key? key, required this.channelName, required this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}
class _VideoCallState extends State<VideoCall> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
RtcEngine? _engine;
#override
void dispose() {
// clear users
_users.clear();
// destroy sdk
_engine?.leaveChannel();
_engine?.destroy();
super.dispose();
}
#override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
Future<void> initialize() async {
if (APP_ID.isEmpty) {
setState(() {
_infoStrings.add(
'APP_ID missing, please provide your APP_ID in settings.dart',
);
_infoStrings.add('Agora Engine is not starting');
});
return;
}
await _initAgoraRtcEngine();
_addAgoraEventHandlers();
await _engine?.enableWebSdkInteroperability(true);
VideoEncoderConfiguration configuration = VideoEncoderConfiguration();
configuration.dimensions = const VideoDimensions(); //(1920,1080)
await _engine?.setVideoEncoderConfiguration(configuration);
await _engine?.joinChannel(Token, widget.channelName, null!, 0);
}
Future<void> _initAgoraRtcEngine() async {
_engine = await RtcEngine.create(APP_ID);
await _engine?.enableVideo();
await _engine?.setChannelProfile(ChannelProfile.LiveBroadcasting);
await _engine?.setClientRole(widget.role);
}
void _addAgoraEventHandlers() {
_engine?.setEventHandler(RtcEngineEventHandler(error: (code) {
setState(() {
final info = 'onError: $code';
_infoStrings.add(info);
});
}, joinChannelSuccess: (channel, uid, elapsed) {
setState(() {
final info = 'onJoinChannel: $channel, uid: $uid';
_infoStrings.add(info);
});
}, leaveChannel: (stats) {
setState(() {
_infoStrings.add('onLeaveChannel');
_users.clear();
});
}, userJoined: (uid, elapsed) {
setState(() {
final info = 'userJoined: $uid';
_infoStrings.add(info);
_users.add(uid);
});
}, userOffline: (uid, elapsed) {
setState(() {
final info = 'userOffline: $uid';
_infoStrings.add(info);
_users.remove(uid);
});
}, firstRemoteVideoFrame: (uid, width, height, elapsed) {
setState(() {
final info = 'firstRemoteVideo: $uid ${width}x $height';
_infoStrings.add(info);
});
}));
}
List<Widget> _getRenderViews() {
final List<StatefulWidget> list = [];
if (widget.role == ClientRole.Broadcaster) {
list.add(RtcLocalView.SurfaceView());
}
_users.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
add(RtcLocalView.SurfaceView());
}
_users.forEach((int uid) => list.add(RtcRemoteView.SurfaceView(uid: uid)));
return list;
}
pubspec.yaml file packages
How to solve this "The named parameter 'channelId' is required, but there's no corresponding argument. (Documentation) Try adding the required argument" error?
You just need to provide channelid to SurfaceView see the example in the official package site

What does the setState method do and why does it throw an error?

The error in setState method, I don't get the point the error.
Could you explain that and what does it mean and do? >>> setState((){_ _availableBiometric = availableBiometric
});
Is it right way like this? >>> setState(() {
_canCheckBiometric = _canCheckBiometric;
});
In the below, full code. Thanks.
void main() => runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: FingerprintApp(),
));
class FingerprintApp extends StatefulWidget {
const FingerprintApp({Key? key}) : super(key: key);
#override
State<FingerprintApp> createState() => _FingerprintAppState();
}
class _FingerprintAppState extends State<FingerprintApp> {
LocalAuthentication auth = LocalAuthentication();
late bool _canCheckBiometric;
late List<BiometricType> _availableBiometrics;
String autherized = "Not autherized";
Future<void> _checkBiometric() async{
bool canCheckBiometric;
try{
canCheckBiometric = await auth.canCheckBiometrics;
} on PlatformException catch(e) {
print(e);
}
if(!mounted) return;
setState(() {
_canCheckBiometric = _canCheckBiometric;
});
}
void _getAvailableBiometrics() async{
List<BiometricType> availableBiometric;
try{
availableBiometric = await auth.getAvailableBiometrics();
} on PlatformException catch(e) {
print(e);
}
if(!mounted) return;
setState(() {
_availableBiometric = availableBiometric. //Here, It has error.
});
}
You should move the setState between the try..catch. It's going to be like the following:
class FingerprintApp extends StatefulWidget {
const FingerprintApp({Key? key}) : super(key: key);
#override
State<FingerprintApp> createState() => _FingerprintAppState();
}
class _FingerprintAppState extends State<FingerprintApp> {
LocalAuthentication auth = LocalAuthentication();
late bool _canCheckBiometric;
late List<BiometricType> _availableBiometrics;
String autherized = "Not autherized";
Future<void> _checkBiometric() async {
bool canCheckBiometric;
try {
canCheckBiometric = await auth.canCheckBiometrics;
if (!mounted) return;
setState(() {
_canCheckBiometric = canCheckBiometric;
});
} on PlatformException catch (e) {
print(e);
}
}
void _getAvailableBiometrics() async {
List<BiometricType> availableBiometric;
try {
availableBiometric = await auth.getAvailableBiometrics();
if (!mounted) return;
setState(() {
_availableBiometrics = availableBiometric;
});
} on PlatformException catch (e) {
print(e);
}
}

State error was called without a registered event handler

This is the code for the event file
import 'package:flutter/foundation.dart';
abstract class AuthEvent {}
class InitEvent extends AuthEvent {}
class SubmitEvent extends AuthEvent {
final String email;
final String password;
SubmitEvent({#required this.email, #required this.password});
}
This is how the InitEvent was called...
import 'auth_event.dart';
import 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthStates> {
AuthBloc() : super(WaitingAuth());
Stream<AuthStates> mapEventToState(AuthEvent event) async* {
yield WaitingAuth();
switch (event.runtimeType) {
case InitEvent:
SharedPreferences prefs = await SharedPreferences.getInstance();
bool login = prefs.getBool('login');
if (login == null || !login) {
prefs.clear();
yield Initialization();
break;
} else {
String token = prefs.getString('token');
String tokenJWT = prefs.getString('tokenJWT');
if (token == null ||
tokenJWT == null ||
token.isEmpty ||
tokenJWT.isEmpty) {
yield Initialization();
} else {
setToken(token);
setJWTToken(tokenJWT);
final response = await Api.getAccount();
if (response is Account) {
final sensorResponse = await Api.getDevices();
if (sensorResponse is List<Sensor>) {
yield SuccessAuth(account: response, sensors: sensorResponse);
} else {
yield SuccessAuth(account: response, sensors: []);
}
} else {
yield Initialization();
}
}
}
break;
case SubmitEvent:
Login screen snippet for InitEvent
#override
void initState() {
_authBloc = AuthBloc();
_authBloc.add(InitEvent());
_passwordFocusNode = FocusNode();
_emailController = TextEditingController();
_passController = TextEditingController();
super.initState();
}
Then in the login screen, InitEvent was called but there is the error of unregistered handler. I don't know what it means. Any help would be appreciated.

No implementation found for method listen on channel for ConnectionStatus library

I'm trying to use FlutterCheckInternetConnectivity on our application, after run application i get this error:
plugins.flutter.io/connectivity_status:
MissingPluginException(No implementation found for method listen on channel
plugins.flutter.io/connectivity_status)
on this part of code:
void dispose() {
connectionChangeController.close();
}
ConnectionStatusSingleton class:
class ConnectionStatusSingleton {
static final ConnectionStatusSingleton _singleton = new ConnectionStatusSingleton._internal();
ConnectionStatusSingleton._internal();
static ConnectionStatusSingleton getInstance() => _singleton;
bool hasConnection = false;
StreamController connectionChangeController = new StreamController.broadcast();
final Connectivity _connectivity = Connectivity();
void initialize() {
_connectivity.onConnectivityChanged.listen(_connectionChange);
checkConnection();
}
Stream get connectionChange => connectionChangeController.stream;
void dispose() {
connectionChangeController.close();
}
void _connectionChange(ConnectivityResult result) {
checkConnection();
}
Future<bool> checkConnection() async {
bool previousConnection = hasConnection;
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
hasConnection = true;
} else {
hasConnection = false;
}
} on SocketException catch(_) {
hasConnection = false;
}
if (previousConnection != hasConnection) {
connectionChangeController.add(hasConnection);
}
return hasConnection;
}
}
my implemented this library:
main() {
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
connectionStatus.initialize();
runApp(MaterialApp(
...
));
}
_FragmentPostsState widget class:
class _FragmentPostsState extends State<FragmentPosts> {
StreamSubscription _connectionChangeStream;
bool isOffline = false;
#override
void initState() {
super.initState();
ConnectionStatusSingleton connectionStatus = ConnectionStatusSingleton.getInstance();
_connectionChangeStream = connectionStatus.connectionChange.listen(connectionChanged);
}
#override
Widget build(BuildContext context) {
return (isOffline)
? Center(...)
: PostPage();
}
void connectionChanged(dynamic hasConnection) {
setState(() {
print('connection changed ...');
isOffline = !hasConnection;
});
}
}
I had this same problem and eventually I restarted the app from command-line and this solved the problem.