Permalink
Browse files

Add Activity to onActivityResult listener interface

Summary:
The Android lifecycle is weird: turns out `onActivityResult` is called before `onResume`. This means `getCurrentActivity()` could return the wrong instance, or `null` if the activity was destroyed. To give developers access to the Activity receiving the result (which is also about to become the current activity), pass it as an argumento the listener.

Fixes github issue #8694.

Reviewed By: donyu

Differential Revision: D3704141

fbshipit-source-id: e7e00ccc28114f97415e5beab8c9b10cb1e530be
1 parent d22003a commit fbd2e139103e3d520f6dfc009d6200f8b8168e35 @foghina foghina committed with Facebook Github Bot 6 Aug 13, 2016
@@ -121,7 +121,7 @@ protected void onDestroy() {
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (getReactNativeHost().hasInstance()) {
getReactNativeHost().getReactInstanceManager()
- .onActivityResult(requestCode, resultCode, data);
+ .onActivityResult(getPlainActivity(), requestCode, resultCode, data);
}
}
@@ -146,7 +146,11 @@ public abstract void onHostResume(
*/
public abstract void onHostDestroy(Activity activity);
- public abstract void onActivityResult(int requestCode, int resultCode, Intent data);
+ public abstract void onActivityResult(
+ Activity activity,
+ int requestCode,
+ int resultCode,
+ Intent data);
public abstract void showDevOptionsDialog();
/**
@@ -607,9 +607,9 @@ private void moveToBeforeCreateLifecycleState() {
}
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (mCurrentReactContext != null) {
- mCurrentReactContext.onActivityResult(requestCode, resultCode, data);
+ mCurrentReactContext.onActivityResult(activity, requestCode, resultCode, data);
}
}
@@ -2,17 +2,19 @@
package com.facebook.react.bridge;
+import android.app.Activity;
import android.content.Intent;
/**
- * Listener for receiving activity events.
+ * Listener for receiving activity events. Consider using {@link BaseActivityEventListener} if
+ * you're not interested in all the events sent to this interface.
*/
public interface ActivityEventListener {
/**
* Called when host (activity/service) receives an {@link Activity#onActivityResult} call.
*/
- void onActivityResult(int requestCode, int resultCode, Intent data);
+ void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data);
/**
* Called when a new intent is passed to the activity
@@ -2,16 +2,23 @@
package com.facebook.react.bridge;
+import android.app.Activity;
import android.content.Intent;
/**
* An empty implementation of {@link ActivityEventListener}
*/
public class BaseActivityEventListener implements ActivityEventListener {
- @Override
+ /**
+ * @deprecated use {@link #onActivityResult(Activity, int, int, Intent)} instead.
+ */
+ @Deprecated
public void onActivityResult(int requestCode, int resultCode, Intent data) { }
@Override
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { }
+
+ @Override
public void onNewIntent(Intent intent) { }
}
@@ -205,9 +205,9 @@ public void destroy() {
/**
* Should be called by the hosting Fragment in {@link Fragment#onActivityResult}
*/
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
for (ActivityEventListener listener : mActivityEventListeners) {
- listener.onActivityResult(requestCode, resultCode, data);
+ listener.onActivityResult(activity, requestCode, resultCode, data);
}
}

18 comments on commit fbd2e13

@marcshilling

@foghina is this not a breaking change? How can I make my module support 0.33 while also being backwards compatible?

@satya164
Contributor

@marcshilling There are 2 methods, one with the old signature marked as deprecated. So you should be able to use the old signature until its removed

@foghina
Contributor

It is a breaking change if you were using ActivityEventListener directly, instead of BaseActivityEventListener. Sorry, but there was no other way. Consider using the base class in the future to avoid compilation errors as we might change the interface in the future.

@subratpanda1
subratpanda1 commented on fbd2e13 Sep 13, 2016 edited

I am getting crash on invoking JS callback from onActivityResult after upgrading to 0.33.0 .

Stack Trace:
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: com.<****>, PID: 13496
AndroidRuntime: java.lang.AbstractMethodError: abstract method "void com.facebook.react.bridge.ActivityEventListener.onActivityResult(android.app.Activity, int, int, android.content.Intent)"
AndroidRuntime: at com.facebook.react.bridge.ReactContext.onActivityResult(ReactContext.java:210)
AndroidRuntime: at com.facebook.react.XReactInstanceManagerImpl.onActivityResult(XReactInstanceManagerImpl.java:612)
AndroidRuntime: at com.facebook.react.ReactActivityDelegate.onActivityResult(ReactActivityDelegate.java:134)

@marcshilling
marcshilling commented on fbd2e13 Sep 13, 2016 edited

@satya164 @foghina but even using BaseActivityEventListener, when running on < RN 0.33, the code won't compile because the new onActivityResult method signature does not exist. Am I missing something?

EDIT: Ah, I guess I can just not mark the new signature as @Override and it works on both 33 and below. Sweet!

@cbrevik
Contributor

@marcshilling Would you have to remove the @Override on the old signature as well then? If not then it will probably throw a compiler exception at 33 and above?

@marcshilling

@cbrevik not required (because the old signature is still defined as deprecated), but I went ahead and did it to prevent issues after it eventually goes away. Tested on both 33 and 32 and it works great.

@foghina
Contributor

You shouldn't have to remove any @Override. You should be able to compile against the newest RN but run on older RN. This is how Android works as well: you always compile against the newest SDK but put runtime checks in to ensure compatibility with older versions. In this case that would be implementing the old callback to simply call the new one.

@foghina
Contributor

I wouldn't worry about it though, I'd just make it work with the latest RN only and if people aren't willing to upgrade they can use the older version of your library as well.

@lekenny

@subratpanda1 I catch the same problem as you. how did you solve.

@subratpanda1

Could not solve. I reverted back to 0.32.0.

@satya164
Contributor
satya164 commented on fbd2e13 Sep 16, 2016 edited

Just updated to 0.33.0. Getting the following,

Process: chat.belong.hello, PID: 23792
java.lang.AbstractMethodError: abstract method "void com.facebook.react.bridge.ActivityEventListener.onActivityResult(android.app.Activity, int, int, android.content.Intent)"
    at com.facebook.react.bridge.ReactContext.onActivityResult(ReactContext.java:210)
    at com.facebook.react.XReactInstanceManagerImpl.onActivityResult(XReactInstanceManagerImpl.java:612)
    at com.facebook.react.ReactActivityDelegate.onActivityResult(ReactActivityDelegate.java:134)
    at com.facebook.react.ReactActivity.onActivityResult(ReactActivity.java:77)
    at chat.belong.hello.MainActivity.onActivityResult(MainActivity.java:64)
    at android.app.Activity.dispatchActivityResult(Activity.java:6470)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:3716)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3763)
    at android.app.ActivityThread.-wrap16(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1403)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5443)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

The code in MainActivity.java is the following,

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        MainApplication.getCallbackManager().onActivityResult(requestCode, resultCode, data);
    }
@satya164
Contributor

@foghina Any idea what's happening here?

@eronisko
Contributor

It is a breaking change if you were using ActivityEventListener directly, instead of BaseActivityEventListener.

I'm guessing lots of people would have been using ActivityEventListener because even the 0.34 docs describe it as the way to add native modules. There is no mention of the BaseActivityEventListener class anywhere in the docs.

@foghina
Contributor

@eronisko thanks for the heads-up, I'll update the docs.

@xiaobuu

I met the same problem as @subratpanda1. Still not working in 0.34.0

@vyky
vyky commented on fbd2e13 Sep 26, 2016

I'm getting the same error as @subratpanda1

I'm sorry but this hack affect more bad then good. Please consider revert back.

@satya164
Contributor

@subratpanda1 @xiaobuu @vyky I found that a module was still using the old API. The error went away after updating the module to use the new API.

Please sign in to comment.