I'm trying to use dart's mirror API to dynamically invoke a function.
How can I obtain the result that's returned from the doWork method when invoking it via an InstanceMirror
class MyData {
String someString;
}
class MyService {
Future<MyData> doWork() async {
print('doing work');
return await Future(() => MyData()..someString = 'my result');
}
}
void main() async {
var instance = MyService();
var mirrror = reflect(instance);
var result = mirrror.invoke(#doWork, []);
}
I can see that "doing work" gets printed to the console so I know it's being invoked, but I'm struggling to interpret the result from the invoke function.
The value are inside the InstanceMirror in the property reflectee. So something like this:
import 'dart:mirrors';
class MyData {
String? someString;
}
class MyService {
Future<MyData> doWork() async {
print('doing work');
return await Future(() => MyData()..someString = 'my result');
}
}
void main() async {
var instance = MyService();
var mirrror = reflect(instance);
var result = mirrror.invoke(#doWork, <dynamic>[]);
var resultValue = await (result.reflectee as Future<MyData>);
print(resultValue.someString); // my result
}
Related
I'm trying to implement an event callback directly in the constructor, but for some reason it does not compile and I do not understand what's the issue with my code.
abstract class Base {
final Future<bool>? onMagic;
Base({
this.onMagic
});
Future<void> doSomething() async {
if(onMagic != null) {
// does not work... why?
// final useMagic = await onMagic!();
onMagic?.then((magic) {
if(magic) print("TODO make something magical");
});
}
}
}
class RealMagic extends Base {
RealMagic() : super(
// Error: The argument type 'Future<bool> Function()' can't be assigned to the parameter type 'Future<bool>?'.
onMagic: () async => await _magic();
);
Future<bool> _magic() async {
return true;
}
}
I inlined the error above. If that's not possible which alternatives do I have to handle the optional callback?
The problem is with the type of the onMagic. It's not a Future<bool>, it should be a Future<bool> Function()?
abstract class Base {
final Future<bool> Function()? onMagic;
Base({this.onMagic});
Future<void> doSomething() async {
onMagic?.call().then((magic) {
if (magic) print("TODO make something magical");
});
}
}
class RealMagic extends Base {
RealMagic()
: super(
onMagic: () async => await _magic(),
);
static Future<bool> _magic() async { // Made this static so it can be accessed in the constructor
return true;
}
}
I would like to pass some initial information into a singleton in dart.
Unfortunately, the information I like to access is null (see dartpad output below)
It seems like I get a new instance of my object and not the singleton but I can not wrap my head around it. Any idea?
ElmCommandProvider.fromMetaData
ElmCommandProvider._internal()
ElmCommandProvider._init
ElmCommandProvider()
null
This is the code which can be pasted in DartPad
class Command {
Command(this.i);
final int i;
}
class MetaData {
MetaData(this.i);
final int i;
}
class ElmCommandProvider {
List<Command> commandsList;
bool _lock = false;
static Map<String, MetaData> _metaDataPool;
factory ElmCommandProvider.fromMetaData(Map<String, MetaData> metaDataPool) {
print('ElmCommandProvider.fromMetaData');
assert(!_singleton._lock, "it's a singleton that can't re-defined");
ElmCommandProvider._metaDataPool = metaDataPool;
_singleton._lock = true;
ElmCommandProvider._init();
return _singleton;
}
factory ElmCommandProvider() {
print('ElmCommandProvider()');
return _singleton;
}
static final ElmCommandProvider _singleton =
new ElmCommandProvider._internal();
ElmCommandProvider._internal() {
print('ElmCommandProvider._internal()');
}
ElmCommandProvider._init() {
print('ElmCommandProvider._init');
commandsList =
_metaDataPool.values.map((bloc) => Command(bloc.i)).toList();
}
}
void main() {
ElmCommandProvider.fromMetaData({'1': MetaData(1), '2': MetaData(2)});
print( ElmCommandProvider().commandsList);
}
_init() should not be a constructor. Or at least there is no need for it to be one and it's confusing you. It should be changed to a static method or a private instance method.
When you do commandsList= in ElmCommandProvider._init(), commandsList is referring to the commandsList instance variable in the new ElmCommandProvider object you're creating with the constructor. You likely actually mean to modify the singleton's commandsList so you should have been doing singleton.commandsList = instead of just commandsList =.
Example working code with static method:
class Command {
Command(this.i);
final int i;
}
class MetaData {
MetaData(this.i);
final int i;
}
class ElmCommandProvider {
List<Command> commandsList;
bool _lock = false;
static Map<String, MetaData> _metaDataPool;
factory ElmCommandProvider.fromMetaData(Map<String, MetaData> metaDataPool) {
print('ElmCommandProvider.fromMetaData');
assert(!_singleton._lock, "it's a singleton that can't re-defined");
ElmCommandProvider._metaDataPool = metaDataPool;
_singleton._lock = true;
_init();
return _singleton;
}
factory ElmCommandProvider() {
print('ElmCommandProvider()');
return _singleton;
}
static final ElmCommandProvider _singleton =
new ElmCommandProvider._internal();
ElmCommandProvider._internal() {
print('ElmCommandProvider._internal()');
}
static _init() {
print('ElmCommandProvider._init');
_singleton.commandsList =
_metaDataPool.values.map((bloc) => Command(bloc.i)).toList();
}
}
void main() {
ElmCommandProvider.fromMetaData({'1': MetaData(1), '2': MetaData(2)});
print( ElmCommandProvider().commandsList);
}
Example working code with private instance method:
class Command {
Command(this.i);
final int i;
}
class MetaData {
MetaData(this.i);
final int i;
}
class ElmCommandProvider {
List<Command> commandsList;
bool _lock = false;
static Map<String, MetaData> _metaDataPool;
factory ElmCommandProvider.fromMetaData(Map<String, MetaData> metaDataPool) {
print('ElmCommandProvider.fromMetaData');
assert(!_singleton._lock, "it's a singleton that can't re-defined");
ElmCommandProvider._metaDataPool = metaDataPool;
_singleton._lock = true;
_singleton._init();
return _singleton;
}
factory ElmCommandProvider() {
print('ElmCommandProvider()');
return _singleton;
}
static final ElmCommandProvider _singleton =
new ElmCommandProvider._internal();
ElmCommandProvider._internal() {
print('ElmCommandProvider._internal()');
}
void _init() {
print('ElmCommandProvider._init');
commandsList =
_metaDataPool.values.map((bloc) => Command(bloc.i)).toList();
}
}
void main() {
ElmCommandProvider.fromMetaData({'1': MetaData(1), '2': MetaData(2)});
print( ElmCommandProvider().commandsList);
}
String empName;
Future<List> getUserData() async{
final response = await http.post("http://172.16.161.34:8080/ebs/cfs/android_test_app/accessfile.php?q=getUserData",body:{
"emp_id": widget.empId,
});
var dataUser = jsonDecode(response.body);
empName = dataUser[0]['name'];
return null;
}
How to display the variable "empName" in line 2 to line 70 "child: Text('')"
Full code on Pastebin
Try this way.. make pojo class for response data like this way..
class UserData {
final int albumId;
final int id;
final String title;
final String url;
final String thumbnailUrl;
UserData({this.albumId, this.id, this.title, this.url, this.thumbnailUrl});
factory UserData.fromJson(Map<String, dynamic> json) {
return new UserData(
albumId: json['albumId'],
id: json['id'],
title: json['title'],
url: json['url'],
thumbnailUrl: json['thumbnailUrl']);
}
}
make method for api call..
Future<UserData> fetchData() async {
var result = await get('https://jsonplaceholder.typicode.com/photos');
if (result.statusCode == 200) {
return UserData.fromJson(json.decode(result.body));
} else {
// If that response was not OK, throw an error.
throw Exception('Failed to load post');
}
}
after that make global object that fetch data..
Future<UserData> userDataList;
on Button click ..
userDataList = fetchData();
after that you want to print data..
userDataList.then((userData){
print(userData.title);
});
First of all you getUserData() function never returns anything. It seems like you only need the name so this function could look like this:
Future<String> getUserData() async{
final response = await http.post("http://172.16.161.34:8080/ebs/cfs/android_test_app/accessfile.php?q=getUserData",body:{
"emp_id": widget.empId,
});
var dataUser = jsonDecode(response.body);
return dataUser[0]['name'];
}
Then to set the empName variable you should use setState().
So change your afterFirstLayout() method to this:
#override
void afterFirstLayout(BuildContext context) async {
// Calling the same function "after layout" to resolve the issue.
getUserData().then( (userName) {
setState(() {
empName = userName;
});
});
}
Also you seem to want to reload the name once you press the IconButton.
So you might want to override your code with this:
IconButton(icon: Icon(Icons.shopping_cart),
onPressed:() {
getUserData().then( (userName) {
setState(() {
empName = userName;
});
});
},
),
Is there any benefit in using completers when you can return an asynchronous callback function(which will return a future).
Example:
Future function() {
return this.socket.request(successCallBack: (response) {
.......
return true;
}); // async call.
against
Future function() {
Completer c = new Completer();
this.socket.request( .. (...){// async callback.
c.complete(xyz);
});
return c.future;
}
Here, The futures return xyz value in both instances. Is it a style preference?
A completer is for more complex scenarios, for example when you want to complete a future in another method than where you create it. In your example the completer is redundant.
class MyComponent {
Completer _initDoneCompleter;
MyComponent() {
Completer _initDoneCompleter = new Completer();
someStream.listen(_eventHandler);
}
void _eventHandler(e) {
if(e.someProperty == 'someValue') {
_initDoneCompleter.complete(e.someProperty);
}
}
static Future<MyComponent> createNew() async {
var c = new MyComponent();
await c.initDoneCompleter.future;
return c;
}
}
void main() async {
var c = await MyComponent.createNew();
}
I want to wrote method which call all function in class:
class Example extends MyAbstractClass {
void f1(){...}
void f2(){...}
void f3(){...}
Example(){
callAll();//this call f1(), f2() and f3().
}
}
I have problem in this part of code:
reflectClass(this.runtimeType).declarations.forEach((Symbol s, DeclarationMirror d) {
if (d.toString().startsWith("MethodMirror on ")) {
String methodName = d.toString().substring(16).replaceAll("'", "");
print(methodName);
// How to call function by name methodName?
}
});
instead of
if (d.toString().startsWith("MethodMirror on ")) {
you can use
if (d is MethodMirror) {
You need an InstanceMirror of an instance of the class. I think in your case this would be
var im = reflect(this).invoke(d.simpleName, []);
im.declarations.forEach((d) ...
see also How can I use Reflection (Mirrors) to access the method names in a Dart Class?
Using dson you can do:
library example_lib;
import 'package:dson/dson.dart';
part 'main.g.dart';
#serializable
class Example extends _$ExampleSerializable {
Example() {
_callAll();
}
fn1() => print('fn1');
fn2() => print('fn2');
fn3() => print('fn3');
fn4() => print('fn4');
_callAll() {
reflect(this).methods.forEach((name, method) {
if(name != '_callAll') this[name]();
});
}
}
main(List<String> arguments) {
_initMirrors();
new Example();
}