I know that we can pass data from Flutter to Native Android, like #UpaJah mentioned in one of his answers:
How to pass a message from Flutter to Native?
But i want to get a response from native android so that i can update my UI accordingly in Flutter. I just have to get response from native by any means. How can i do that?
Update:
I tried this piece of code as #liu-silong had mentioned in the answer:
bleChannel.invokeMethod("updateUI", 1, new MethodChannel.Result() {
#Override
public void success(#Nullable Object result) {
Log.d(TAG, "success");
}
#Override
public void error(String errorCode, #Nullable String errorMessage, #Nullable Object errorDetails) {
Log.d(TAG, "errorCode: " + errorCode);
}
#Override
public void notImplemented() {
Log.d(TAG, "notImplemented");
}
});
Now my code gets inside notImplemented callback. Any suggestion?
You can call Dart methods through MethodChannel on the Android side
Android:
private MethodChannel channel;
channel = new MethodChannel(getFlutterEngine().getDartExecutor(), "channel_name");
// invoke dart method (in the main thread)
channel.invokeMethod("foo", new HashMap<String, Object>());
Dart
final MethodChannel channel = new MethodChannel("channel_name");
channel.setMethodCallHandler(_methodCallHandler);
Future<dynamic> _methodCallHandler(MethodCall call) {
if(call.method == 'foo'){
// do sth...
}
}
Or you can also use EventChannel.
https://github.com/liusilong/stack_q
Related
I'm trying to implement android widgets in android native code of flutter. I want to send the data from flutter to the android code every 30 mins to update the android widget to show the data. How do I send data to the android side from flutter side.
use MethodChannel
static const platform = const MethodChannel('test.flutter.native');
pass to Data(Flutter -> Android)
try {
final int result = await platform.invokeMethod('nativeCode');
} catch (e) {
print("Error : ${e.toString}");
}
Get Data in Android File
private static final String CHANNEL = "test.flutter.native";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall call, Result result) {
// Note: this method is invoked on the main thread.
// TODO
}
});
}
See the link for more information
https://docs.flutter.dev/development/platform-integration/platform-channels?tab=type-mappings-java-tab
In an android app I was able to subscribe to a pusher channel and log out the event data. So now I want to be able to trigger events from the same application. I don't find documentation relating to this on the web.
Am I missing something because I also have a node express app in which I'm able to trigger and subscribe to events in the same app.
Below is my code for the Android app, I'm looking to trigger an event in the "responseAFunc" function which is wired to a button click.
I have also left out the all import statements and package statements.
public class MainActivity extends Activity {
private Button responseA;
private ActivityMainBinding binding;
private Pusher pusher;
private Channel channel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
responseA = binding.responseA;
PusherOptions options = new PusherOptions();
options.setCluster("eu");
pusher = new Pusher("*****************",options);
pusher.connect( new ConnectionEventListener() {
#Override
public void onConnectionStateChange(ConnectionStateChange change) {
Log.e("Pusher"," changed to " + change.getCurrentState());
}
#Override
public void onError(String message, String code, Exception e) {
Log.e("Pusher" ," connecting! msg:" + message + " " + code);
Log.e("Pusher", e.getMessage());
}
}, ConnectionState.ALL);
channel = pusher.subscribe("to-pusher");
channel.bind("message", new SubscriptionEventListener() {
#Override
public void onEvent(PusherEvent event) {
Log.i("Pusher", event.getData());
}
});
}
public void responseAFunc(View view){
// Trigger event
}
}
Hope this makes sense and HELLO from South Africa !!!
Hello from Amsterdam!
What you are looking for is "client events". Here are the docs: https://pusher.com/docs/channels/using_channels/events/#triggering-client-events
It's very easy: Once you got an instance for a channel you can just call the "trigger" method on it. Here are the docs for java: https://github.com/pusher/pusher-websocket-java#triggering-events
The harder part is that it will only work on private and presence channels. And then you will need to implement authentication. https://pusher.com/docs/channels/server_api/authenticating-users/
In my android application I have a screen where I have 3 spinners that need to be
filled from APIs call.
static List<TripCode> tripCodeList = new ArrayList<>();
static List<Fleet> truckList = new ArrayList<>();
static List<Trailer> trailerList = new ArrayList<>();
And I don't want to inflate the layout unless I get the response from all the 3 different API calls so this is what I'm doing
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
if (MyApplication.isConnected()) {
getTripCodes();
} else {
Toast.makeText(this, "No internet Connection", Toast.LENGTH_LONG).show();
setContentView(R.layout.no_internet_connection);
}
}
Basically , I removed setContentView(R.layout.activity_create_trip);
from onCreate() And I called getTripCodes()
here's the code for getTripCodes()
public void getTripCodes() {
MyApplication.showProgressDialog(getString(R.string.please_wait), this);
IMyAPI iMyAPI = MyApplication.getIMyAPI();
Call<List<TripCode>> call = iMyAPI.getTripCodes();
call.enqueue(new Callback<List<TripCode>>() {
#Override
public void onResponse(Call<List<TripCode>> call, Response<List<TripCode>> response) {
if (response.isSuccessful() && response.body() != null) {
tripCodeList = response.body();
Log.d("test", "getTripCodes success = " + tripCodeList.size());
getTrucks();
} else {
MyApplication.dismissProgressDialog();
}
}
#Override
public void onFailure(Call<List<TripCode>> call, Throwable t) {
MyApplication.dismissProgressDialog();
}
});
}
So in the success of the call I'm calling the other function getTrucks() which also get result from API and in the success it will call getTrailers()
But I think it's a waste of time, because I can call the three function all together in parallel, and then check if all the list are filled or not.
But I don't know how to do it. How can I check if all the calls are success? And if one of them has failed, how will I know which one exactly failed?
I Believe for your problem you can easily use Retrofit 2.6.0 which has coroutine support and you can declare all the function's as suspended function's and dispatch them with async/launch dispatcher and if you want to wait for some result in some case use await() to wait for the result.
And use RxJava/liveData for responsive UI
sample code for you will look like
//maybe from Activity for ViewModel you can use ViewModelScope
GlobalScope.launch{
result1= async{ getTripCodes() }
result2= async{ getTrucks() }
result3= async{ getTrailers() }
doSomethingWithTripCodes(result1.await())
doSomethingWIthTrucks(result2.await())
doSomethingTrailers(result3.await())
}
Reference:
post1
I have seen plenty of examples of how to use Android TextToSpeak in an Activity, and have also managed to get this to work just fine. I've also managed to get it to work using a bound service in a plugin, but it seems overcomplicated for my purposes. Here is my VoiceService class:
public class VoiceService : IVoiceService, TextToSpeech.IOnInitListener
{
public event EventHandler FinishedSpeakingEventHandler;
private TextToSpeech _tts;
public void Init()
{
// Use a speech progress listener so we get notified when the service finishes speaking the prompt
var progressListener = new SpeechProgressListener();
progressListener.FinishedSpeakingEventHandler += OnUtteranceCompleted;
//_tts = new TextToSpeech(Application.Context, this);
_tts = new TextToSpeech(Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity, this);
_tts.SetOnUtteranceProgressListener(progressListener);
}
public void OnInit(OperationResult status)
{
// THIS EVENT NEVER FIRES!
Console.WriteLine("VoiceService TextToSpeech Initialised. Status: " + status);
if (status == OperationResult.Success)
{
}
}
public void Speak(string prompt)
{
if (!string.IsNullOrEmpty(prompt))
{
var map = new Dictionary<string, string> { { TextToSpeech.Engine.KeyParamUtteranceId, new Guid().ToString() } };
_tts.Speak(prompt, QueueMode.Flush, map);
Console.WriteLine("tts_Speak: " + prompt);
}
else
{
Console.WriteLine("tts_Speak: PROMPT IS NULL OR EMPTY!");
}
}
/// <summary>
/// When we finish speaking, call the event handler
/// </summary>
public void OnUtteranceCompleted(object sender, EventArgs e)
{
if (FinishedSpeakingEventHandler != null)
{
FinishedSpeakingEventHandler(this, new EventArgs());
}
}
public void Dispose()
{
//throw new NotImplementedException();
}
public IntPtr Handle { get; private set; }
}
Note that the OnInit method never gets called.
In my viewmodel I'd like to do this:
_voiceService.Init();
_voiceService.FinishedSpeakingEventHandler += _voiceService_FinishedSpeakingEventHandler;
... and then later ...
_voiceService.Speak(prompt);
When I do this I get these messages in the output:
10-13 08:13:59.734 I/TextToSpeech( 2298): Sucessfully bound to com.google.android.tts
(happens when I create the new TTS object)
and
10-13 08:14:43.924 W/TextToSpeech( 2298): speak failed: not bound to TTS engine
(when I call tts.Speak(prompt))
If I was using an activity I would create an intent to get this to work, but I'm unsure how to do that in a plugin.
Thanks in advance,
David
Don't implement Handle yourself, instead derive from Java.Lang.Object
public class VoiceService : Java.Lang.Object, IVoiceService, TextToSpeech.IOnInitListener
and remove your Dispose() and Handle implementation
More info here: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/android_callable_wrappers/
Also, I suggest you take an async approach when implementing your service, which would make calling it from view-model something like
await MvxResolve<ITextToSpeechService>().SpeakAsync(text);
I am using Codenameone and ZXing to read a QRCode. When I call the Scanner, my mobile opens the QRCode reader application and I get to read the QRCode except that when android takes me back to my app it goes through init then start statuses. Which moves me back to the login form of my application instead of continuing filling the form that I was in.
Any help on what to do to stay in the same form? Is there something I'm doing wrong? Thanks in advance.
EverproX.addMessage("Before Scan\n");
CodeScanner.getInstance().scanQRCode(new ScanResult() {
public void scanCompleted(String contents, String formatName, byte[] rawBytes) {
EverproX.addMessage("Scan Completed "+contents);
}
public void scanCanceled() {
EverproX.addMessage("Scan Cancelled");
}
public void scanError(int errorCode, String message) {
EverproX.addMessage("Scan Error "+errorCode+" "+message);
}
});
EverproX can be seen as a log class.
By analyzing our log we can say that as soon as we call the CodeScanner.getInstance().scanQRCode() the application is called for 'Destroy'. Then after the scanning is done it goes again through the init and start. It never goes into the scanComplete scanCanceled or scanError Callbacks.
Is it normal that the App is destroyed upon call of CodeScanner? Many thanks.
Inside your codenameone project, you should find a class named (for example MyApp.java) based on your app's name, modify the code to read something like similar to this:
public class MyApp {
private Form current;
public void init(Object context) {
// Pro users - uncomment this code to get crash reports sent to you automatically
Display.getInstance().addEdtErrorHandler(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
evt.consume();
Log.p("Exception in AppName version " + Display.getInstance().getProperty("AppVersion", "Unknown"));
Log.p("OS " + Display.getInstance().getPlatformName());
Log.p("Error " + evt.getSource());
Log.p("Current Form " + Display.getInstance().getCurrent().getName());
Log.e((Throwable) evt.getSource());
Log.sendLog();
}
});
}
public void start() {
if (current != null) {
current.show();
return;
}
new StateMachine("/theme");
}
public void stop() {
current = Display.getInstance().getCurrent();
}
public void destroy() {
current = null;
}
}