in a flutter, I execute multiple functions on initState. Like this:-
#override
void initState() {
super.initState();
function1();
function2();
function3();
function4();
}
in case the function2() has some errors it affects function3(),function4() also. How do we avoid this?
You can call try in each functions to avoid getting stop incase of getting error:
void function1(){
try {
//put you code hear
} catch (e) {
print("e = $e");
}
}
You have to use try & catch but, there is a way to write only at one place !
create a extension on Function to call it & absorb the error if any occures in it.
Here is a example:
import 'dart:developer';
void f1() => print('f1');
void f2() => throw 'STOP';
void f3() => print('f3');
extension FunctionUtils on Function {
void callAndAbsorbError() {
try {
this.call();
} catch (e, st) {
log("Error in $this", error: e, stackTrace: st);
}
}
}
void main(List<String> arguments) {
f1.callAndAbsorbError();
f2.callAndAbsorbError();
f3.callAndAbsorbError();
}
This way you don't need to write try catch in every function you create. AND all your functions will execute for sure.
More about extensions : vandad's blog
Related
I am playing around with dart syntax
And I was trying this code:
void main() {
print("Hello to demo");
try{
throw Test("hello");
}
on Test catch(Test e, StackTrace s){ //error on this line
print("error message is ${(e).message}");
}
}
class Test{
String? message;
Test(this.message);
}
The error message I get is
'catch' must be followed by '(identifier)' or '(identifier, identifier)'.
No types are needed, the first is given by 'on', the second is always 'StackTrace'
I know that dart is strongly typed language but the same time explicitly defining types is optional, but I don't know why am I getting this message here, are there some situations (like the catch here) where even specifying a type is forbidden and not even optional?
p.s.: I am reading the documentation here
Simply catch is a keyword, not a function, and it is designed in a way that you can't set parameter types. You have to use it as documented here, like:
try {
// ยทยทยท
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
Your code works this way:
void main() {
print("Hello to demo");
try {
throw Test("hello");
}
on Test catch(e, s){
print("error message is ${(e).message}");
print("stacktrace is ${(s)}");
}
}
class Test {
String? message;
Test(this.message);
}
A data class in Dart:
import 'package:validate/validate.dart';
class AuthUser {
final String email, token, username, bio, image;
AuthUser(this.email, this.token, this.username, this.bio, this.image) {
Validate.isEmail(this.email);
}
#override
String toString() {
return 'AuthUser{email: $email, token: $token, username: $username, bio: $bio, image: $image}';
}
}
where Validate.isEmail will throws an Error when failed to match:
static void matchesPattern(String input, RegExp pattern,[String message = DEFAULT_MATCHES_PATTERN_EX]) {
if (pattern.hasMatch(input) == false) {
throw new ArgumentError(message);
}
}
static void isEmail(String input,[String message = DEFAULT_MATCHES_PATTERN_EX]) {
matchesPattern(input,new RegExp(PATTERN_EMAIL),message);
}
Now I want to use an elegant way to new this class.
When using Scala, I can use Try(new AuthUser(...)) and patten-matching it.
And in Dart, first I tried RxDart,
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
Observable.just(AuthUser("email", "token", "username", "bio", "img"))
.doOnError((e, s) => print("oh no"))
.listen((e) => print(e.toString()));
});
}
Not work, the test failed for the error(which means RxDart doesn't catch errors at all!!!)
And I want to try Future, failed also.
And I want to use dartz, but I am worried because there is just one maintainer...
Any advice?
If you are OK with using Future what's wrong with this advice: Using Future.sync() to wrap your code? The code will look like this:
void main() {
var f = Future.sync(() {AuthUser("email", "token", "username", "bio", "img"); });
f.then((v) => print("Value: " + v.toString())).catchError((e) => print("Failure: " +e.toString()));
}
The main trick is that Future.sync effectively enables lazy evaluation of the parameter but you have to pass your parameter wrapped in a function. This is actually the same trick Scala compiler does for Try (i.e. for call-by-name parameters) but takes adding a few brackets around.
If you only want the basic functionality of returning either type based on whether an exception occurred or not then you can easily create a utility class such as below.
Otherwise I recommend #SergGr's answer about using Future.sync since it gives you more monadic like pipeline.
void main() {
Try<Error, void> result = Try.it(() => Validate.isEmail("test-example.com"));
if (result is Success) {
print("Good");
} else if (result is Failure) {
print("Error: " + result.exception().toString());
}
}
typedef TryExec<V> = V Function();
abstract class Try<E extends Error, V> {
static Try<E, V> it<E extends Error, V>(TryExec<V> fn) {
try {
return Try.success(fn());
} catch (e) {
return Try.failure(e);
}
}
static Try<E, V> failure<E extends Error, V>(Error e) {
return new Failure(e);
}
static Try<E, V> success<E extends Error, V>(V v) {
return new Success(v);
}
}
class Failure<E extends Error, V> extends Try<E, V> {
final E _e;
Failure(this._e);
E exception() => _e;
}
class Success<E extends Error, V> extends Try<E, V> {
final V _v;
Success(this._v);
V value() => _v;
}
I am switching from async tasks to rxjava2 and have some issues with my code tests.
I have a room table of elements that have a certain monetary amount. On a usercontrol that is called DisplayCurrentBudget, a sum of all amounts should be displayed. This number must refresh everytime a new element is inserted. I tackled the requirement in two ways, but both produce the same result: My code does not care if the database is updated, it only updates when the fragment is recreated (onCreateView).
My first attempt was this:
//RxJava2 Test
Observable<ItemS> ItemObservable = Observable.create( emitter -> {
try {
List<ItemS> movies = oStandardModel.getItemsVanilla();
for (ItemS movie : movies) {
emitter.onNext(movie);
}
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<ItemS> disposable = ItemObservable.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<ItemS>() {
public List<ItemS> BadFeelingAboutThis = new ArrayList<ItemS>();
#Override
public void onNext(ItemS movie) {
// Access your Movie object here
BadFeelingAboutThis.add(movie);
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
oBinding.DisplayCurrentBudget.setText(Manager.GetBigSum(BadFeelingAboutThis).toString());
}
});
I already was uncomfortable with that code. My second attempt produces the exact same result:
Observable<BigDecimal> ItemObservable2 = Observable.create( emitter -> {
try {
BigDecimal mySum = oStandardModel.getWholeBudget();
emitter.onNext(mySum);
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
});
DisposableObserver<BigDecimal> disposable = ItemObservable2.
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribeWith(new DisposableObserver<BigDecimal>() {
#Override
public void onNext(BigDecimal sum) {
// Access your Movie object here
oBinding.DisplayCurrentBudget.setText(sum.toString());
}
#Override
public void onError(Throwable e) {
// Show the user that an error has occurred
}
#Override
public void onComplete() {
// Show the user that the operation is complete
}
});
Any obvious issues with my code?
Thanks for reading, much appreciate it!
Edit:
I was asked what Manager.GetBigSum does, it actually does not do much. It only adds BigDecimal-Values of an Item list.
public static BigDecimal GetBigSum(List<ItemS> ListP){
List<BigDecimal> bigDList = ListP.stream().map(ItemS::get_dAmount).collect(Collectors.toList());
return bigDList.stream()
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
Further, I simplified the query. But it still does not care about DB updates, only about fragment recreation:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
Your rx logic has no error. That should be internal error in your getWholeBudget.
But why you write rx so complex?
For your case, you can just write:
Single.fromCallable(() -> oStandardModel.getItemsVanilla())
.map(Manager::GetBigSum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(sum.toString()),
e -> log.error(e));
I solved it this way:
oStandardModel.getItemJointCatLive().observe(this, new Observer<List<ItemJointCat>>() {
#Override
public void onChanged(#Nullable final List<ItemJointCat> oItemSP) {
Single.fromCallable(() -> oStandardModel.getWholeBudget())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
e -> oBinding.DisplayCurrentBudget.setText(e.toString())
);
}
});
My mistake was that I assumed RXjava2 does not need an onchanged event...now i just use onchanged event of livedata observer to trigger a simple rxjava2 query.
Do you think there is anything wrong with that approach?
I have two operations step_1() and step_2() and want to execute step_2() AFTER step_1().
With normal java this would be:
step_1();
step_2();
With vertx I have to use vertx-compose(). Am I right?
According to https://groups.google.com/forum/#!topic/vertx/FuvlPLpoGOA, I dont need Futures for sequential code.
"If you want to do each request sequencially you dont need futures."
So how can I do that without using futures?
I dont know, if this matters: My Vertx from which this code is executed is a "Worker"-Verticle.
#Override
public void start(Future<Void> fut) throws IOException {
Future<Void> step_1 = Future.future();
step_1.compose(res -> {
// If the future succeeded
Future<Void> step_2 = step_1();
step_2.compose(res2 -> {
step_2();
}, Future.future().setHandler(handler -> {
// If the future failed
}));
//I dont need that
}, Future.future().setHandler(handler -> {
// If the future failed
}));
}
public void step_1(){
..
}
public void step_2(){
..
}
Is this the right and shortest (!) way?
Below is an example of chaining of Future, I have made the example very trivial nonetheless it showcases the concept.
#RunWith(VertxUnitRunner.class)
public class Chaining {
private Vertx vertx = Vertx.vertx();
#Test
public void futures_chaining(TestContext context) throws Exception {
Async async = context.async();
firstOperation()
.compose((outcome) -> {
System.out.println(outcome);
return secondOperation();
})
.compose(outcome -> {
System.out.println(outcome);
/*
For stopping unit test we are returning this future
for production use-case this would be Future.succeededFuture
or Future.failedFuture depending on your method outcomes
*/
return Future.future(handle -> async.complete());
});
}
private Future<String> firstOperation() {
Future<String> future = Future.future();
vertx.setTimer(1000, delay -> future.complete("First Operation Complete"));
return future;
}
private Future<String> secondOperation() {
Future<String> future = Future.future();
vertx.setTimer(1000, delay -> future.complete("Second Operation Complete"));
return future;
}
}
"If you want to do each request sequencially you dont need futures."
No, it's not. In asynchronous frameworks like Vert.x, input/output operations are non-blocking. It means, that if you call few asynchronous operations, they'll start working simultaneously. And if you want to do few requests sequentially, then you should use futures or callbacks to execute new request only after previous one finished successfully.
Check this code with futures, newer version with RxJava 2 and article about project.
#Override
public Future<Optional<Todo>> getCertain(String todoID) {
Future<Optional<Todo>> result = Future.future();
redis.hget(Constants.REDIS_TODO_KEY, todoID, res -> {
if (res.succeeded()) {
result.complete(Optional.ofNullable(
res.result() == null ? null : new Todo(res.result())));
} else
result.fail(res.cause());
});
return result;
}
#Override
public Future<Todo> update(String todoId, Todo newTodo) {
return this.getCertain(todoId).compose(old -> {
if (old.isPresent()) {
Todo fnTodo = old.get().merge(newTodo);
return this.insert(fnTodo)
.map(r -> r ? fnTodo : null);
} else {
return Future.succeededFuture();
}
});
}
RxJava exists specifically to compose async events: http://vertx.io/docs/vertx-rx/java/
Assuming both step_1() and step_1() aren't designed to return results (i.e. they effectively return void) then you could change them to return Observable or Single and chain them together similar to this:
step_1().doOnSuccess(this::step_2()).subscribe(/* control resumes here */);
RxJava (or rather, reactive programming in general) takes a little bit to wrap your head around it, but I would strongly recommend using it if you're planning to chain together async operations.
Pass step_2 as argument to step_1
#Override
public void start(Future<Void> fut) throws IOException {
step_1(step_2);
}
private void step_1(Runnable function){
someAsynccall("some-arg", response -> {
function.run();
}).end();
}
private void step_2(){
// do something
}
I have written this code to test how custom exceptions are working in the dart.
I'm not getting the desired output could someone explain to me how to handle it??
void main()
{
try
{
throwException();
}
on customException
{
print("custom exception is been obtained");
}
}
throwException()
{
throw new customException('This is my first custom exception');
}
You can look at the Exception part of A Tour of the Dart Language.
The following code works as expected (custom exception has been obtained is displayed in console) :
class CustomException implements Exception {
String cause;
CustomException(this.cause);
}
void main() {
try {
throwException();
} on CustomException {
print("custom exception has been obtained");
}
}
throwException() {
throw new CustomException('This is my first custom exception');
}
You don't need an Exception class if you don't care about the type of Exception. Simply fire an exception like this:
throw ("This is my first general exception");
You can also create an abstract exception.
Inspiration taken from TimeoutException of async package (read the code on Dart API and Dart SDK).
abstract class IMoviesRepoException implements Exception {
const IMoviesRepoException([this.message]);
final String? message;
#override
String toString() {
String result = 'IMoviesRepoExceptionl';
if (message is String) return '$result: $message';
return result;
}
}
class TmdbMoviesRepoException extends IMoviesRepoException {
const TmdbMoviesRepoException([String? message]) : super(message);
}
Try this Simple Custom Exception Example for Beginners
class WithdrawException implements Exception{
String wdExpMsg()=> 'Oops! something went wrong';
}
void main() {
try {
withdrawAmt(400);
}
on WithdrawException{
WithdrawException we=WithdrawException();
print(we.wdExpMsg());
}
finally{
print('Withdraw Amount<500 is not allowed');
}
}
void withdrawAmt(int amt) {
if (amt <= 499) {
throw WithdrawException();
}else{
print('Collect Your Amount=$amt from ATM Machine...');
}
}