React Native handle on java side addListener - android

I use addListener method of NativeEventEmitter to add listener from JavaScript to native side.
import {NativeModules, NativeEventEmitter, EmitterSubscription} from 'react-native';
const CoreBridge = NativeModules.Core;
class Core extends NativeEventEmitter {
constructor() {
super(CoreBridge);
}
addListener(event: CoreEvent, handler: Function): EmitterSubscription {
return super.addListener(event, handler);
}
}
export default new Core();
Can I handle addListener() on the native Java side? I have try with this but it's not called:
#ReactMethod
public void addListener(String event) {
//register native listener for event emitting
}
For iOS this can be done:
#pragma mark - RCTEventEmitter
- (NSArray<NSString > )supportedEvents {
return #[EVENT_ONE,
EVENT_TWO];
}
/// This method will be called when the first event listener is added.
- (void)startObserving {}
/// This method will be called when the last event listener is removed.
- (void)stopObserving {}
Can I have the same event listeners handling for Android?

Related

Nativescript - Android disabling physical device back button

I am trying to disabling the physical device back in android only in some screens. Trying the below code is not working. Any idea?
import { RouterExtensions } from "nativescript-angular";
import * as application from "application";
import { AndroidApplication, AndroidActivityBackPressedEventData } from "application";
import { isAndroid } from "platform";
export class ItemComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
if (!isAndroid) {
return;
}
application.android.on(AndroidApplication.activityBackPressedEvent, (data: AndroidActivityBackPressedEventData) => {
data.cancel = true; // prevents default back button behavior
});
}
}
#Override
public void onBackPressed() {
if (!shouldAllowBack()) {
doSomething();
} else {
super.onBackPressed();
}
}
Add this code in your activity-
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Your Code Here. Leave empty if you want nothing to happen on back press.
}
For more information visit this link.
Back button is controlled at Activity level, NativeScript uses one single Activity and all your pages / routes are fragments inside that.
So you don't have to call it on every page / component. Add the listener to your app component and check the router to know which page you are at and cancel the back event.
Use location and check if location consists the desired path(as mentioned in routing file) where you want to use your custom function.
import { Location } from '#angular/common';
constructor(private _location: Location
){}
if (application.android) {
application.android.on(AndroidApplication.activityBackPressedEvent, (data: AndroidActivityBackPressedEventData) => {
const path = this._location.path();
console.log(`path i s--> ${path}`);
switch (path) {
case '/Screen 1':
data.cancel = true;
break;
case '/Screen 2':
//do something else
break;
});
}

how send event from some class?

I have some class that implement a state machine.
When some state is change i want to send some event to all the classes that listen to this event
How can i do it ?
I looking for some simple way like that do it on C#
public event EventHandler NotifyStatusChange;
private void NotifyStateChanged()
{
if( NotifyStatusChange != null )
{
NotifyStatusChange( this, new ObjectStatusEventArgs( lastStatus, currentStatus ) );
}
}

React-native key board events

I am writing a react native app and need to implement keyboard events inside components.
I tried with following code and did not success.
import { DeviceEventEmitter } from 'react-native';
export default class KeyEvent {
static onKeyDownListener(cb) {
KeyEvent.removeKeyDownListener();
console.log('Key Down');
this.listenerKeyDown = DeviceEventEmitter.addListener('onKeyDown', cb);
}
static removeKeyDownListener() {
if (this.listenerKeyDown) {
this.listenerKeyDown.remove();
}
}
static onKeyUpListener(cb) {
console.log('Key up');
KeyEvent.removeKeyUpListener();
this.listenerKeyUp = DeviceEventEmitter.addListener('onKeyUp', cb);
}
static removeKeyUpListener() {
if (this.listenerKeyUp) {
this.listenerKeyUp.remove();
}
}
}
Call inside componentDidMount function relevant component as follows.
componentDidMount() {
console.log('componentDidMount');
// if you want to react to keyDown
KeyEvent.onKeyDownListener((keyCode) => {
console.log(`Key code pressed: ${keyCode}`);
});
// if you want to react to keyUp
KeyEvent.onKeyUpListener((keyCode) => {
console.log(`Key code pressed: ${keyCode}`);
});
}
componentWillUnmount() {
console.log('componentWillUnmount');
// if you are listening to keyDown
KeyEvent.removeKeyDownListener();
// if you are listening to keyUp
KeyEvent.removeKeyUpListener();
}
Can anyone help me to fix this or suggest any other way of doing this. I need to press a button on enter key down.
As per react native doc, you can attach below events to keyboard.
keyboardWillShow
keyboardDidShow
keyboardWillHide
keyboardDidHide
keyboardWillChangeFrame
keyboardDidChangeFrame
So if you want pressed key event then you need to attach event to input field like below.
<TextInput
onKeyPress={this.handleKeyDown}
placeholder="Enter text here..."
/>
handleKeyDown: function(e) {
if(e.nativeEvent.key == "Enter"){
dismissKeyboard();
}
},

React Native - Module Lifecycle - Dispose resources on "Reload"

I am using a react native module (https://github.com/rusel1989/react-native-bluetooth-serial) for Bluetooth communication with an Arduino.
Eveything works just fine. But when I press "Reload" or the application reloads due to Live Reload being enabled, the onDestroy method of the module is not called. Because of that, the sockets (and streams) are no correctly disposed.
When the reload is finished, I can no longer open a bluetooth socket. It requires me to disable and enable bluetooth, or to restart the application.
Is there ant callback or method I could implement that would correctly dispose these sockets when I reload my application?
Ok after spending time in react-native code I found the answer to this:
On iOS:
You'll have to implement a method called invalidate in your RCTBridgeModule implementation:
That will run whenever the context is destroyed (the app is reloaded) and it will look like this:
- (void)invalidate
{
// disconnect bluetooth here
}
Here's an example of how I did it on iOS.
On Android:
you'll have to implement the onCatalystInstanceDestroy method inside your ReactContextBaseJavaModule and it will look like this:
#Override
public void onCatalystInstanceDestroy() {
// disconnect bluetooth here
}
Here's an example of how I did it on Android.
It seems we can use #Override public void onCatalystInstanceDestroy() {} without the need of implementing anything.
That method will be called before the current JS bundle is destroyed.
on iOS
- (instancetype)init
{
self = [super init];
NSLog(#"whatever you want");
return self;
}
- (void)dealloc
{
// by the way, you do not need the following line because of ARC
// [super dealloc];
NSLog(#"whatever you want");
}
I prefer use dealloc rather than invalidate
because react-native api may change in the future...
on android
import com.facebook.react.bridge.LifecycleEventListener;
import android.util.Log;
public class YourModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
...
YourModule(ReactApplicationContext reactContext) {
super(reactContext);
reactContext.addLifecycleEventListener(this);
this.reactContext = reactContext;
Log.d("YourModuleLog", "whatever you want");
}
#Override
public void onHostResume() {}
#Override
public void onHostPause() {}
#Override
public void onHostDestroy() {
Log.d("YourModuleLog", "not trigger after fast reload");
}
#Override
public void onCatalystInstanceDestroy() {
Log.d("YourModuleLog", "whatever you want");
}
}
only override onCatalystInstanceDestroy does not work for me
unless I also add LifecycleEventListener.

ScrollView Custom renderer no longer working on Xamarin Forms 2.x

Want to add simple paging to ScrollView.
On iOS it was easy adding a customer renderer like this:
[assembly:ExportRenderer (typeof(ScrollView), typeof(JustEat.Ordertracker.Touch.Renderers.ExtendedScrollViewRenderer))]
namespace JustEat.Ordertracker.Touch.Renderers
{
public class ExtendedScrollViewRenderer : ScrollViewRenderer
{
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
UIScrollView iosScrollView = (UIScrollView)NativeView;
iosScrollView.PagingEnabled = true;
iosScrollView.ShowsHorizontalScrollIndicator = false;
}
}
}
So doesn't look like android has paging flag so was going to implement with touch events or similar, but can't get any events to trigger on Android side. So have tried hooking up events and overriding:
[assembly:ExportRenderer (typeof(ScrollView), typeof(JustEat.Ordertracker.Touch.Renderers.ExtendedScrollViewRenderer))]
namespace JustEat.Ordertracker.Touch.Renderers
{
public class ExtendedScrollViewRenderer : ScrollViewRenderer
{
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
global::Android.Widget.ScrollView droidScrollView = (global::Android.Widget.ScrollView)this;
droidScrollView.HorizontalScrollBarEnabled = false;
droidScrollView.Drag += delegate
{
Console.WriteLine("Drag");
};
}
public override bool OnTouchEvent(global::Android.Views.MotionEvent ev)
{
Console.WriteLine("OnTouchEvent");
return base.OnTouchEvent(ev);
}
}
}
The OnElementChanged definitely gets called as I hit a breakpoint, but the events do nothing, neither does setting HorizontalScrollBarEnabled to false, or even setting .Enabled to false. It's like I have access to a different object?
Found an excellent git repo using same technique to do same thing
https://github.com/chrisriesgo/xamarin-forms-carouselview/issues/24
which works great with 1.x version of forms it uses, but upgrade it to 2.x and it no longer works for above reason.

Categories

Resources