getCurrentActivity in ReactContextBaseJavaModule returns null - react-native

I'm coding a native Android module with React Native 0.46 and I have trouble getting the current activity instance from the module.
I have a class extending ReactContextBaseJavaModule, which contains a built-in getCurrentActivity() method. However, each time I call this method, I get a null.
I think it's because I'm calling this in my module constructor, which is executed at the start of the Android application, maybe before an Activity is instantiated ?
If you guys know a clean way to access the current Activity instance from within the module (without having to store an Activity instance at some point and passing it around, if possible), I'll be glad !

According to these posts on the react-native GitHub page, it is by design that you cannot access the current activity in the constructor of a native module. The modules may be used across Activities, and may be created before an associated Activity has resumed.
The expectation is that you can use getCurrentActivity when needed during operations, for example from any #ReactMethod in the module.

same as Myk Willis answer, getCurrentActivity can be accessed inside #ReactMethod like this example:
public class ExampleModule extends ReactContextBaseJavaModule {
Activity activity;
#ReactMethod(isBlockingSynchronousMethod = true)
public void MinimizeExample(String params) {
activity = getCurrentActivity(); // get current activity
}
}

Related

React: Calling JS function after bridge has been destroyed --- How to find which function

I'm working on an update for our app. I've added a HeadlessTask and I've started seeing this warning in the console:
React: Calling JS function after bridge has been destroyed
How can I get the name of the function being executed?
From the error message I assume you're in java (react-native Android):
When you reload on react-native, what happens behind the scenes is that the react context is getting destroyed, and a new one is being created.
That error get's thrown whenever a react-native Native Module is trying to do work, by using the old react context (the one that was valid before the reload).
The last time I saw that error it also included an explanation as to which module tried to do work by using the old context. Typically it's the RCTDeviceEventEmitter module trying to send a message to javascript.
You'll have to open logcat on Android studio and read the full error message.
p.s: If you're using react-native-navigation in your project, (after you discover which module is the trouble maker by using the logcat), make sure to search on their issues as they are heavily using the native side of react-native android, and I've seen lot's of similar issues so far.
Never found a good solution to this until recently, so thought I'd put this here in case it helps someone else. I finally got around this error by doing the following:
public class RNMyNativeModule extends ReactContextBaseModule {
private ReactApplicationContext currentContext;
public RNMyNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
currentContext = reactContext;
}
public void myEmitFn(String emitMe) {
currentContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("RNMyNativeModuleEvent", emitMe);
}
}
Basically, in your module constructor, make sure you capture the currentContext in it's own variable, and just use that whenever you need it. Otherwise it gets overwritten and destroyed whenever a live reload happens, and getReactApplicationContext() is not actually giving you the current context.

How to access AppCompatActivity from native module?

When I want to create a native bridge for a library, I realize that it need an AppCompatActivity instance as a parameter.
I've spent few hours to find a method that can return an AppCompatActivity instance, but I can't find anything, yet.
P.S. there is getCurrentActivity method, but it return Activity instance, instead of AppCompatActivity

Access the EPartService after an RCP application has initialized

After my application initialized, I'm trying to automatically create a part within a part stack. I need the EPartService for this but I can't think of any way to properly get a hold of this service.
I've tried using the LifeCycle management to get the current IEclipseContext. However, whenever I try to access the service using the context, it's not found.
Any idea how I can do this?
You should be able to inject the EPartService in any of the defined methods in your life cycle class. However you won't be able to show a part until the application startup is complete. So use the App Startup Complete event, by adding a method like this to the life cycle class:
#Optional
#Inject
public void appStartupComplete(#UIEventTopic(UIEvents.UILifeCycle.APP_STARTUP_COMPLETE) Event event,
EPartService partService)
{
....
}

How to select a different module to run when you click the Run button in IntelliJ IDEA?

In my IntelliJ IDEA project, I have 3 modules written in Kotlin:
An HTTP Servlet one.
A desktop swing application; and
A library that contains contracts that the above two listed projects share to talk to each other.
When I click the Run button, it starts the Tomcat server and loads up my servlet project. That is because, and I am guessing here, the new project creation template inside of the IDE created a new Run Configuration for the entire project and it is defined in this run configuration that it must start the module that has the servlet inside it.
Now that the servlet runs fine, I'd like to also run the desktop application written using Swing.
How do I do that? I've done this once before but I have forgotten how I did it.
Do I have to define a new Run Configuation? I tried that this way:
I selected Kotlin from the left pane titled Add New Configuration and specified the name of the class that had the main function, and also the name of the module that had this class.
Here is the source code of my main class.
package bookyard.client;
import javax.swing.SwingUtilities;
public class Program {
public fun main(args : Array<String>) {
SwingUtilities.invokeLater(LoginDialogEventLoop());
}
}
But when I click the Run button after choosing that run configuration's name, the process reports an error that suggests that the class name I specified as having the main function actually does not have the main function, which I am not sure why that is.
The main method needs to be static, and the method you have declared is not. In Kotlin, you can either declare main as a top-level function (outside of a class), or, if you want to keep it inside the class, use the following syntax:
class Program {
companion object {
#JvmStatic fun main(args: Array<String) { ... }
}
}

How do I make Message targets be the only recipent of a targeted Message?

First time poster.
I'm using MVVM-Light with Silverlight 4 and RIA Services. This has been a learning experience! But so far, it's working beautifully. I was wondering two things. Right now, I'm using the Messenger framework to pass EntityObjects back to the ViewModel. For instance, I need to open a View Model with a specific "Course" object. So I instantiate the View, and the View sends a Message to the ViewModel with the Course. I've got a couple questions.
First question: Is this the best way to do this? I don't want to use Prism or Unity or any of those other things because I don't have the time to learn them. (This was, for me, the big draw of MVVM Light. The Light part.) But I couldn't see any other way to pass parameters to the VM Locator.
The second part is, this means I am sending messages from the View to that View's specific ViewModel. My messages look like this:
Tuple<Models.Course, Services.VWDS> courseDomainContextTuple = new Tuple<Models.Course, Services.VWDS>(Course, DomainContext);
NotificationMessage<Tuple<Models.Course, Services.VWDS>> message = new NotificationMessage<Tuple<Models.Course, Services.VWDS>>(this, this.DataContext, courseDomainContextTuple, Models.MessageString.EditCourse);
Messenger.Default.Send<NotificationMessage<Tuple<Models.Course, Services.VWDS>>>(message);
So, as you can see, I'm bundling the Course and the DomainContext (Ah RIA. Why won't you let me get the Context from the EntityObject?) and sending them to the ViewModel (which is "this.DataContext") - and yes, I know I should make a class for that message.
Here's the problem - every object that gets a Course and a DomainContext receives that message, not just the VM that I've designated the Target.
So, second question: Is that by design, or is that a bug, or am I doing something wrong?
Thanks!
To answer your second question, if you're sending a NotificationMessage of a specific type, anything registering for that same message type will receive the message. If you want to limit who receives the message, either create a new message class inheriting from MessageBase or NotificationMessage or whatever, send your message with a Token, or have an if statement in your message receive handler to filter out messages you don't care about.
Messaging is more useful when you need to communicate from one ViewModel to another, or you need to send a message where zero to many things can take action on it. From your View's code behind, I think you should just call your ViewModel directly. Its easy enough - here's how I usually do it in my code.
public partial class ExampleView : UserControl
{
private IExampleViewModel ViewModel
{
get { return this.DataContext as IExampleViewModel; }
}
public ExampleView()
{
InitializeComponent();
// Call directly to my View Model
ViewModel.SomeMethod();
// Register for View Model's event
ViewModel.SomeEvent += ViewModel_SomeEvent;
}
private void ViewModel_SomeEvent(object sender, EventArgs e)
{
// do stuff
}
}
I also included in the example how I handle communications from the ViewModel back to the View - through events.