Giter Site home page Giter Site logo

victoralbertos / rxactivityresult Goto Github PK

View Code? Open in Web Editor NEW
595.0 595.0 72.0 202 KB

A reactive-tiny-badass-vindictive library to break with the OnActivityResult implementation as it breaks the observable chain.

License: Apache License 2.0

Java 100.00%

rxactivityresult's People

Contributors

gitter-badger avatar jm-agrimap avatar jvmname avatar miguelbcr avatar riwnodennyk avatar victoralbertos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxactivityresult's Issues

If the screen has been closed before the second Activity back, then the first Activity will not receive a callback

##Summary
If the screen has been closed before the second Activity back, then the first Activity will not receive a callback

Preconditions


#### Steps to reproduce actual result 1.
---------------------------------------------------------------------------
FirstActivity.class

RxActivityResult.on(this)
                    .startIntent(new Intent(this, SecondActivity.class))
                    .subscribe(new Action1<Result<StartActivity>>() {
                        @Override
                        public void call(Result<StartActivity> startActivityResult) {
                            if (startActivityResult.resultCode() == RESULT_OK) {

                            } else {

                            }
                        }
                    });

---------------------------------------------------------------------------
SecondActivity.class

 //click this button and close the phone screen,the firstActivity will never receive the result
findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Observable.timer(10, TimeUnit.SECONDS)
                       .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<Long>() {
                            @Override
                            public void call(Long aLong) {
                                setResult(RESULT_OK);
                                  finish();
                            }
                        });
            }
        });

Actual result


#### Expected result

The x file [while showing Progress View before start RxResult, slow response, onDestroy dont call ]

Hi

After checking that we had a significant delay since the activity was launched until the result was received, we started to remove and comment all the code, seems that problem happens when ProgressView is visible, we tested on a multitude of devices and it seems that the error is in Samsung, we could not check if the error is a this model in exclusive or in all samsung.

I make a example in a fork

Error - Samsung Galaxy S7 SM-G935F
Checked - Lg nexus, Motorola, Sony Xperia

Thank you in advance.

requestCode parameter not found in Result

The Andorid method does have three parameters in the method onActivityResult: requestCode, resultCode and data.

onActivityResult(int requestCode, int resultCode, Intent data)

However, the Result class does not have these parameters

Is it possible to start an intent with Bundle options?

Is it possible to start an intent with Bundle options?
Such as

public void startActivityForResult(
            @RequiresPermission Intent intent, 
            int requestCode,
            @Nullable Bundle options)

activity.startActivityForResult(intent,requestCode,options)

What happens if activity is destroyed

If you launch an activity B from activity A via this library. After the launch, to claim system resources, android killed both A & holder activity, but not B (as it is the activity interacting with the user).

In this scenario

  1. You will lose reference to onResult of HolderActivity as its not persisted in the bundleonSaveInstanceState
  2. Even if you chose to save onResult during onSaveInstanceState, by the time B is done & HolderActivity is recreated, there is no guarantee you will have access to A & its subscription as activity itself is not present.

As per my understanding, as per the current implementation framework will not work as intended

Fail to propagate result for certain case

We're trying to integrate this library with Google SignIn, and however subscriber gets no result.

After investigation, we found that there's potential issue for this library. For Google SignIn, they use a SignInHubActivity, which presents a dialog then puts itself into pause state. Then when user click on the dialog option, it will set result and finish activity.

@Override public void onActivityPaused(Activity activity) {
liveActivityOrNull = null;
}

At this moment, RxActivityResult.activitiesLifecycle.getLiveActivity() returns null and thus breaks the expected subscription behavior.

Possibly related: #36
Possible fix: use getOLiveActivity instead

What about startActivityForResult

In #3 you talked about startIntentSenderForResult but what an implementation for startActivityForResult a lot of api like the Google login for example requires to call it.

Exception when destroying HolderActivity

When using the v7:25.3.1 app compat libraries I get the following exception when focus is returned back to the original activity.

java.lang.RuntimeException: Unable to destroy activity {com.myproject.mobile.android/rx_activity_result2.HolderActivity}: java.lang.IllegalStateException: Fragment has not been attached yet.
     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5061)
     at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5084)
     at android.app.ActivityThread.access$1700(ActivityThread.java:221)
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1853)
     at android.os.Handler.dispatchMessage(Handler.java:102)
     at android.os.Looper.loop(Looper.java:158)
     at android.app.ActivityThread.main(ActivityThread.java:7224)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
  Caused by: java.lang.IllegalStateException: Fragment has not been attached yet.
     at android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2154)
     at android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:704)
     at rx_activity_result2.RxActivityResult$Builder.getTargetFragment(RxActivityResult.java:146)
     at rx_activity_result2.RxActivityResult$Builder.getTargetFragment(RxActivityResult.java:148)
     at rx_activity_result2.RxActivityResult$Builder.access$100(RxActivityResult.java:50)
     at rx_activity_result2.RxActivityResult$Builder$3.response(RxActivityResult.java:127)
     at rx_activity_result2.HolderActivity.onDestroy(HolderActivity.java:98)
     at android.app.Activity.performDestroy(Activity.java:7102)
     at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1170)
     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5039)
     at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5084) 
     at android.app.ActivityThread.access$1700(ActivityThread.java:221) 
     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1853) 
     at android.os.Handler.dispatchMessage(Handler.java:102) 
     at android.os.Looper.loop(Looper.java:158) 
     at android.app.ActivityThread.main(ActivityThread.java:7224) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

The problem stems from lazy creation of the fragment manager in the new library release.

I had to also address some of my own code which made use of fragment.getChildFragmentManager().getFragments() to check if the fragment isAdded() before requesting a child fragment manager.

Updating the line 137 in RxActivityResult should fix the problem.

if(fragment != null && fragment.getChildFragmentManager() != null) {

to

if(fragment != null && fragment.isAdded() && fragment.getChildFragmentManager() != null) {

need for minSdk>7 ?

Is there a need for the library project to have a higher minSdk value than 7?
It appears to build fine.

Results taking up to 10 seconds

I'm using RxPaparazzo in our app, but the adding picture has severe delays on our Samsung devices, north of 10 seconds.

return RxActivityResult.on(targetUi.activity())
        .startIntent(intent)
        .map(new Func1<Result<Activity>, Intent>() {
            @Override
            public Intent call(Result<Activity> result) {
                return StartIntent.this.getResponse(result);
            }
        });

The map function would take 10 seconds since the Observable was started. Attach sources doesn't work for me so I can't debug further than that.

Support nested fragments

Currently if a fragment has been instantiated as a child fragment from a parent one, there is no callback call for the subscriber fragment child.

Review

Hi, just looking at libraries using RC2 and found these issues.

The emitted field is private and generates an accessor:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/ActivitiesLifecycleCallbacks.java#L57

The same emitted field is not volatile and possibly read in another thread:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/ActivitiesLifecycleCallbacks.java#L70

These fields are also private and generate accessors:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/ActivitiesLifecycleCallbacks.java#L12

liveActivityOrNull is possibly read in another thread and should be volatile:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/ActivitiesLifecycleCallbacks.java#L63

subject could be final:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/RxActivityResult.java#L52

clazz is private and generates an accessor:

https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/RxActivityResult.java#L51
https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/RxActivityResult.java#L100
https://github.com/VictorAlbertos/RxActivityResult/blob/2.x/rx_activity_result/src/main/java/rx_activity_result/RxActivityResult.java#L138

Memory leaks

        this.activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                ActivitiesLifecycleCallbacks.this.liveActivityOrNull = activity;
            }

            public void onActivityStarted(Activity activity) {
            }

            public void onActivityResumed(Activity activity) {
                ActivitiesLifecycleCallbacks.this.liveActivityOrNull = activity;
            }

            public void onActivityPaused(Activity activity) {
                ActivitiesLifecycleCallbacks.this.liveActivityOrNull = null;
            }

            public void onActivityStopped(Activity activity) {
            }

            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
            }

            public void onActivityDestroyed(Activity activity) {
            }
        };

If I finish an activity inside onCreate , the method onActivityPaused won't be called. ActivitiesLifecycleCallbacks.this.liveActivityOrNull don't free the reference to the activity and causes memory leaks!

NullPointerException

in HolderActivity.onCreate(HolderActivity.java:33)
onResult = request.onResult()

compileVersion: 26/27

The library didn't work with compile version android 26 or 27. It stop working on Samsung Devices.

Support for RxJava 2

Any plans to make a library version for usage with RxJava 2?

Btw, great library!

How to start activity without animation

The process of shifting between A and B is no animation
But how to remove animation after using RxActivityResult

RxActivityResult.on(mActivity)
        .startIntent(new Intent(mActivity, SearchActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
                .putExtra("custom picker", mainActivity.isCustomPicker()))
        .subscribe(new Action1<Result<Activity>>() {
            @Override
            public void call(Result<Activity> result) {
                if (result.data() != null) {
                    mainActivity.onReturnCustomPickerRes(
                            result.data().getIntExtra("res", 0));
                }
            }
        });

startActivity

use This

//from    public Builder(T t) 
Activity activity= (Activity) t;
activity.startActivity(new Intent(activity, HolderActivity.class));

replace

activitiesLifecycle.getOLiveActivity().subscribe(new Action1<Activity>() {
                @Override public void call(Activity activity) {
                    activity.startActivity(new Intent(activity, HolderActivity.class));
                }
            });

how to set requestCode ?

the requestCode always 0;

Intent takePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

RxActivityResult.on(this).startIntent(takePhoto)
        .subscribe(result -> {
            Intent data = result.data();
            int resultCode = result.resultCode();
            // the requestCode using which the activity is started can be received here.
            int requestCode = result.requestCode();//why always requestCode= 0?

            if(requestCode == YourActivity.YOUR_REQUEST_CODE)
            {
                // Do Something
            }

            if (resultCode == RESULT_OK) {
                result.targetUI().showImage(data);
            } else {
                result.targetUI().printUserCanceled();
            }
        });

overridePendingTransition

At first thanks for this lib, but i found that can not use it with overridePendingTransition to animate showing activity. Can you check or suggest decision?

Broken behavior with don't keep activities

If you enable don't keep activities on dev settings to simulate such scenario when coming back to MainActivity you would get redirected once more to the camera app and then after taking another photo you get back to MainActivity again but it won't display the picture that was taken

Add support for startIntentSenderForResult

Some apis, like IAB (in app billing), requires to call startIntentSenderForResult instead of calling startActivityForResult.

That's why this needs to be implemented.

AndroidX

Hi! I'm migrating our app to AndroidX, and I was wondering:

  1. do you have a timeline for migrating to this library to AndroidX?
  2. if I submit a PR migrating the lib to AndroidX, what would be the timeline to having it released?

Calling startActivityForResult from service

It would be really useful, as some Android apis require this and often need to be called from a service. To create an invisible Activity for this every time is not as nice, and also would not easily support getting the result in the service... I saw a few solutions out there...:

http://stackoverflow.com/a/38414213
http://stackoverflow.com/a/37754232
http://stackoverflow.com/a/40356400

What do you think? This could be a possible addition to this library?

Thanks for your great work!!

Activity not found exception.

Hi guys, we've been using this library from a while now, and first of all great stuff 👍

Recently we're seeing an error when we start the contacts picker intent on a fragment.

Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.xyz.xyz/rx_activity_result2.HolderActivity}; have you declared this activity in your AndroidManifest.xml?

We're using the support fragment - android.support.v4.app;
ver - implementation 'com.github.VictorAlbertos:RxActivityResult:0.4.5-2.x'
And we're using v 27.1.1 support libraries.

With thanks, any help will be great!

Permission Denial with ACTION_GET_CONTENT

Hello,

I was in the process of using RxActivityResult to change the bad "code + onActivityResult override" pattern.

In particular, using Intent.ACTION_GET_CONTENT provides a SecurityException when trying to read the result.

Code is the following

    Intent pickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
    pickerIntent.addCategory(Intent.CATEGORY_OPENABLE);
    pickerIntent.setType("image/*");
    RxActivityResult.on(this)
      .startIntent(Intent.createChooser(pickerIntent, null))
      .observeOn(AndroidSchedulers.mainThread())
      .subscribe(activityResult -> {
        Intent intent = activityResult.data();
        int resultCode = activityResult.resultCode();
        if (resultCode == Activity.RESULT_OK && intent != null) {
            if (intent.getDataString() != null) {
                  Timber.d("DataString: %s - %s",intent.getDataString(), intent.getData());
                  InputStream inputStream = getContext().getContentResolver().openInputStream(intent.getData());
                  FileOutputStream fos = new FileOutputStream(Utils.genCacheFile());
                  Utils.pipeIOOO(inputStream,fos); // <--- EXCEPTION
             }
         }
       });  

The exception is the following:

java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.impl.MediaContentProvider from ProcessRecord{289c731 31097:com.andreabaccega.myprinter/u0a86} (pid=31097, uid=10086) that is not exported from uid 10065

It looks like that when using ACTION_GET_CONTENT the picker automatically allows permission to the requiring context to access the picked images. see http://stackoverflow.com/questions/38301605/reading-com-google-android-apps-photos-contentprovider-mediacontentprovider-requ
and
http://stackoverflow.com/questions/30572261/using-data-from-context-providers-or-requesting-google-photos-read-permission/30909105#30909105

I also tried using .targetUI() to get the context with no luck. (Expected also since both resultUI() and this are the same object).

Doesn't survive process deaths

Steps to reproduce:

  1. Pick "Using activity"
  2. Pick "Camera"
  3. [Camera started] – Kill app process with ADB
  4. Shoot photo

Results in a crash:

FATAL EXCEPTION: main
Process: io.victoralbertos.app, PID: 3083
java.lang.RuntimeException: Unable to start activity ComponentInfo{io.victoralbertos.app/rx_activity_result.HolderActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'rx_activity_result.OnResult rx_activity_result.Request.onResult()' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2625)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2686)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1440)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:5969)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:801)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:691)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'rx_activity_result.OnResult rx_activity_result.Request.onResult()' on a null object reference
    at rx_activity_result.HolderActivity.onCreate(HolderActivity.java:33)
    at android.app.Activity.performCreate(Activity.java:6669)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2578)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2686) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1440) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:5969) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:801) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:691) 

getTargetFragment() NPE in some fragments

Buenas tardes Victor! :-)
Sorry, can't do demo project now. But it seems, like when you have complex UI there's NPE in that code:

        @Nullable private Fragment getTargetFragment(List<Fragment> fragments) {
            if (fragments == null) return null;

            for (Fragment fragment : fragments) {
                if(fragment != null && fragment.isVisible() && fragment.getClass() == clazz) {
                    return fragment;
      // NPE IS HERE SEE           |
      //                           v
                } else if (fragment.getChildFragmentManager() != null) {     //   <------ THAT LINE
                    List<Fragment> childFragments = fragment.getChildFragmentManager().getFragments();
                    return getTargetFragment(childFragments);
                }
            }

            return null;
        }

(RxActivityResult.java line 139)

It seems, like fragments array have target Fragment, but ALSO has null element inside. So if you just skipped null-element - NPE would dismiss.

In my UI I have fragments (cause of navigation drawer) and nested fragments (in ViewPager). RxPaparazzo code is called from nested fragment.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.