Flutter setMethodCallHandler not call its argument - android

iam trying to open a flutter screen from native android
so iam trying to use MethodChannel for returning data to dart then invoke method that's gonna navigate me to the current screen
but my code is not working
this is my code
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
String channelName = "app_channel";
MethodChannel methodChannel = new MethodChannel(flutterEngine.getDartExecutor(), channelName);
methodChannel.invokeMethod("openCaller", false, new MethodChannel.Result() {
#Override
public void success(#Nullable Object result) {
Log.i("fromInvoke","success" + result.toString());
}
#Override
public void error(String errorCode, #Nullable String errorMessage, #Nullable Object errorDetails) {
Log.i("fromInvoke","failed" + errorMessage);
}
#Override
public void notImplemented() {
Log.i("fromInvoke","not implemented");
}
});
}
}
static const platform =
const MethodChannel('app_channel');
#override
void initState() {
super.initState();
platform.setMethodCallHandler(invokedMethods);
}
and this is a global function
Future<dynamic> invokedMethods(MethodCall methodCall) async {
switch (methodCall.method) {
case "openCaller":
print("arrived to open caller");
// Navigator.pushNamed(context, "/ring");
}
}

The method methodChannel.invokeMethod("openCaller", ...) doesn't seem to be triggered on the code snippets you've provided, it's only set inside configureFlutterEngine. You need to invoke the method from Android to call the function you've configured inside the Flutter app. Check this article covering this topic in more detail and with a sample code.

Related

Where does the Callback object come from in the ListenableWorker example?

The Android developer docs show an example of how to use a ListenableWorker. However, despite having added councurrent-futures to my project, I see now relevant Callback object as used in the docs:
#NonNull
#Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
Callback callback = new Callback() {
...
}
Can anyone point me in the right direction? There doesnt seem to be a Callback class in androidx.concurrent.callback at all.
this is literally the only code sample I can find that uses CallbackToFutureAdapter.getFuture at all.
Looking at the documentation to a similar API, it looks to me that Callback
is not an API in itself but a generic representation of any operation with results.
https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter.html
As an example, you could define the callback as follows,
interface AsyncCallback {
void onSuccess(Foo foo);
void onError(Failure failure);
}
And the startWork method as follows
#Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
AsyncCallback callback = new AsyncCallback() {
int successes = 0;
#Override
public void onError(Failure failure) {
completer.setException(failure.getException());
}
#Override
public void onSuccess(Foo foo) {
completer.set(Result.success());
}
};
for (int i = 0; i < 100; ++i) {
downloadAsynchronously("https://www.google.com", callback);
}
return callback;
});
}

RxJava2: execute an async function for every item in a list and wait for callback

I'm struggling with RxJava2. I want to perform a function on each item of a list. This function :
public void function(final Result result) {
FirebaseFirestore.getInstance().collection(COLLECTION_NAME).document(result.getId()).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
// do some operation
}
});
}
This function is async and use FirebaseFirestore.
So I tried to use RxJava2 on my list to call the function for every item:
Observable.fromIterable(resultList)
.concatMap(result -> Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
function(result);
return "ok";
}
}))
.subscribe(r -> {
// do some operation when all firebase async tasks are done
});
The concatMap works and the function is called for every item of the list. The problem is that I need a callback when all firebase async tasks are done.
Any help would be much appreciated.
I'll try to draw a possible solution:
public class Callback implements OnSuccessListener<DocumentSnapshot> {
private final ObservableEmitter<DocumentSnapshot> emitter;
private final boolean last;
public Callback(boolean lastvalue, ObservableEmitter<DocumentSnapshot> e) {
this.last = lastvalue;
this.emitter = e;
}
#Override
public void onSuccess(DocumentSnapshot value) {
emitter.onNext(value);
if (last) {
emitter.onComplete();
}
}
}
Observable<DocumentSnapshot> observable = Observable.create(new ObservableOnSubscribe<DocumentSnapshot>() {
#Override
public void subscribe(ObservableEmitter<DocumentSnapshot> e) throws Exception {
int i = 1;
for (Result result : resultList) {
/* callback object now knows which is the last request so it can emit the onComplete */
Callback callbackInstance = new Callback(resultList.size() == i, e);
i++;
FirebaseFirestore.getInstance().collection(COLLECTION_NAME)
.document(result.getId()).get().addOnSuccessListener(callbackInstance);
}
}
});
then when the subscriber's onComplete action is hit all the requests to Firebase should be completed.

How replace returned observable with a new one RxJava2

I have one case when I need to return an observable immediately, but then replace this observable with another one.
Here is an example
private Flowable<byte[]> mFlowableStream = Flowable.empty();
#Override
public Flowable<byte[]> startStreamRead() {
bindToService();
return mFlowableStream;
}
And then after binding to service I provide it a callback connection like that
#Override
public void bindToService() {
mAppContext.bindService(new Intent(mAppContext,StreamService.class), mServiceConnection, 0);
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
mServiceInterection = ((StreamServiceInterection.LocalBinder) binder).getServiceInteractor();
mStreamDisposable = mServiceInterection.getStream()
.subscribe(new Consumer<byte[]>() {
#Override
public void accept(byte[] data) throws Exception {
}
});
}
What I want to do is to somehow replace returned previously mFlowableStream with a new observable that I got from service.
What are possible strategies to implement this ? Maybe I should return some other value, like Future.
Please suggest how to solve this problem
Thanks
You can use Flowable.create instead of Flowable.empty
Then when new data come, just push to flowable.
Like Example
final ArrayList<FlowableEmitter<Integer>> arrEmitter = new ArrayList<>();
Flowable<Integer> futureFlow = Flowable.create(new FlowableOnSubscribe<Integer>() {
#Override
public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
arrEmitter.add(e); // hold emitter to use later
}
}, BackpressureStrategy.BUFFER);
futureFlow.subscribe(new ResourceSubscriber<Integer>() {
#Override
public void onNext(Integer integer) {
System.out.println("onNext: " + integer);
}
#Override
public void onError(Throwable t) {
}
#Override
public void onComplete() {
System.out.println("onComplete");
}
});
// =========== When data come
FlowableEmitter<Integer> holdEmitter = arrEmitter.get(0);
holdEmitter.onNext(3);
Or use you can use **Subject* type according to your need
Understanding RxJava Subject — Publish, Replay, Behavior and Async Subject

The model layer (MVP) should use the Activity reference

How can I make a proper separation between the Model layer and the View layer, when I have an operation in the Model that needs the current activity instance?
For example, I've integrated Linkedin SDK in my Android app (written in MVP).
In the auth process I have the following code snippet, when init() method's first argument type is Activity:
public void authWithLinkedin(final IAuth listener, Activity activity) {
LISessionManager.getInstance(MyApplication.getContext()).init(activity, buildScope(), new AuthListener() {
#Override
public void onAuthSuccess() {
listener.onSuccess();
}
#Override
public void onAuthError(LIAuthError error) {
listener.onError();
}
}, true);
}
If my Model layer should get to know Android framework components, what options do I have left to preserve the MVP architecture clean?
You can use software conventions / principles like
"dependency inversion principle"
"ports and adapters"
Your model layer should not know about Android if you can avoid it is the point.
Try something like this:
Model:
private final SocialLoginProvider socialLoginProvider;
public MyModel(SocialLoginProvider socialLoginProvider) {
this.socialLoginProvider = socialLoginProvider;
}
public void authWithLinkedin(final IAuth listener) {
socialLoginProvider.init(buildScope(), new SocialLoginProvider.Listener() {
#Override
public void onAuthSuccess() {
listener.onSuccess();
}
#Override
public void onAuthError() {
listener.onError();
}
}, true);
}
Factory:
public MyModel getModel(Context context) {
LISessionManager li = LISessionManager.getInstance(context);
SocialLoginProvider provider = new LinkedInSocialLoginProvider(context, li);
return new MyModel(provider);
}
Interface:
public interface SocialLoginProvider {
void init(Scope scope, Listener listener);
interface Listener {
void onAuthSuccess();
void onAuthError();
}
}
Adapter for SocialLoginProvider:
public class LinkedInSocialLoginProvider implements SocialLoginProvider {
private final Context context;
private final LISessionManager linkedInSessionManager;
public LinkedInSocialLoginProvider(Context context, LISessionManager linkedInSessionManager) {
this.context = context;
this.linkedInSessionManager = linkedInSessionManager;
}
#Override
public void init(Scope scope, Listener listener) {
linkedInSessionManager.init(context, scope,
new AuthListener() {
#Override
public void onAuthSuccess() {
listener.onSuccess();
}
#Override
public void onAuthError(LIAuthError error) {
listener.onError();
}
}, true);
}
}
Ideally it is ok to have Android Framework components in the Model layer. For example you will need the Context to store/access data locally using getDefaultSharedPreferences(Context) and/or to manage local DB using SQLiteOpenHelper.
The LISessionManager.getInstance(MyApplication.getContext()).init seems to be like a BroadcastReceiver as it is a type of listener that receives a particular result from an outside component. To handle such a case you can refer to this

Syncano async query with 'where()' filter

I'm using Syncano latest Android SDK (4.0.6).
Is there a way to have a async query with parameters?
Syncano.please(User.class).where()
Doesn't have a method to run it asynchronously.
But
Syncano.getInstance().getObjects(User.class)
Which has 'sendAsync()' but doesn't have 'where()' constrain.
Docs specifies:
Syncano.please(User.class).getAsync(callback);
But I don't see it in code only getAll().
You can make an async call when using please(). Just pass SyncanoCallback object.
Syncano.please(Item.class).get(new SyncanoListCallback<Item>() {
#Override
public void success(ResponseGetList<Item> response, List<Item> result) {
}
#Override
public void failure(ResponseGetList<Item> response) {
}
});
You're right that async get() method is missing when using where(). It has to be fixed in the library, but you can make this call anyway saving the reference to RequestBuilder.
RequestBuilder<Item> please = Syncano.please(Item.class);
please.where().eq(Item.COLUMN_NUMBER, 11);
please.get(new SyncanoListCallback<Item>() {
#Override
public void success(ResponseGetList<Item> response, List<Item> result) {
}
#Override
public void failure(ResponseGetList<Item> response) {
}
});
You can also use where(), without using please(). It will look like this:
Where<Item> where = new Where<>();
where.eq(Item.COLUMN_NUMBER, 11);
Syncano.getInstance().getObjects(Item.class).setWhereFilter(where).sendAsync(new SyncanoListCallback<Item>() {
#Override
public void success(ResponseGetList<Item> response, List<Item> result) {
}
#Override
public void failure(ResponseGetList<Item> response) {
}
});

Categories

Resources