Giter Site home page Giter Site logo

florent37 / inlineactivityresult Goto Github PK

View Code? Open in Web Editor NEW
274.0 8.0 28.0 450 KB

Receive the activity result directly after the startActivityForResult with InlineActivityResult

License: MIT License

Kotlin 15.94% Java 83.07% Shell 1.00%
android activity result intent callback direct rx lambda kotlin coroutine

inlineactivityresult's Introduction

Inline Activity Result

Language

Work in progress

Receive the activity result directly after the startActivityForResult with InlineActivityResult, choose your way :

No need to override Activity or FragmentonActivityResult(code, permissions, result)using this library, you just have to execute InlineActivityResult's methods This will not cut your code flow

Supports startIntentSenderForResult

General Usage (cross language)

Download

dependencies {
    implementation 'com.github.florent37:inline-activity-result:(lastest version)'
}
startForResult(this, new Intent(MediaStore.ACTION_IMAGE_CAPTURE), new ActivityResultListener() {
      @Override
      public void onSuccess(Result result) {
          //the started activity result is RESULT_OK
      }

      @Override
      public void onFailed(Result result) {
          //the started activity result is RESULT_CANCEL
      }
});

Kotlin-Coroutines

launch(UI) {
   try {
       val result = startForResult(Intent(MediaStore.ACTION_IMAGE_CAPTURE))

       //use the result, eg:
       val imageBitmap = result.data?.extras?.get("data") as Bitmap
       resultView.setImageBitmap(imageBitmap)
   } catch (e: InlineActivityResultException) {

   }
}

Download

Download

implementation 'com.github.florent37:inline-activity-result-kotlin:(last version)'

Kotlin

startForResult(Intent(MediaStore.ACTION_IMAGE_CAPTURE)) { result ->
     //use the result, eg:
     val imageBitmap = result.data?.extras?.get("data") as Bitmap
     resultView.setImageBitmap(imageBitmap)
}.onFailed { result ->

}

Download

Download

implementation 'com.github.florent37:inline-activity-result-kotlin:(last version)'

RxJava

new RxInlineActivityResult(this).request(new Intent(MediaStore.ACTION_IMAGE_CAPTURE)))
    .subscribe(result -> {
        //use the result, eg:
        Bundle extras = result.getData().getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        resultView.setImageBitmap(imageBitmap);
    }, throwable -> {
        if (throwable instanceof RxInlineActivityResult.Error) {
            final Result result = ((RxInlineActivityResult.Error) throwable).getResult();

        }
    })

Download

implementation 'com.github.florent37:inline-activity-result-rx:(last version)'

Java8

new InlineActivityResult(this)
       .startForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE))
       .onSuccess(result -> {
           //use the result, eg:
           Bundle extras = result.getData().getExtras();
           Bitmap imageBitmap = (Bitmap) extras.get("data");
           resultView.setImageBitmap(imageBitmap);
       })
       .onFail(result -> {
            
       });

Download

Download

implementation 'com.github.florent37:inline-activity-result:(last version)'

Java7

InlineActivityResult.startForResult(this, new Intent(MediaStore.ACTION_IMAGE_CAPTURE), new ActivityResultListener() {
      @Override
      public void onSuccess(Result result) {
          Bundle extras = result.getData().getExtras();
          Bitmap imageBitmap = (Bitmap) extras.get("data");
          resultView.setImageBitmap(imageBitmap);
      }

      @Override
      public void onFailed(Result result) {

      }
});

StartIntentSenderForResult

Also supports startIntentSenderForResult, as example:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 0, intent, 0);

Request request = RequestFabric.create(pendingIntent.getIntentSender(), null, 0, 0, 0, null);

new InlineActivityResult(this)
         .startForResult(request)
         .onSuccess(result -> {
             Bundle extras = result.getData().getExtras();
             Bitmap imageBitmap = (Bitmap) extras.get("data");
             resultView.setImageBitmap(imageBitmap);
          })
          .onFail(result -> {

          });

How to Contribute

We welcome your contributions to this project.

The best way to submit a patch is to send us a pull request.

To report a specific problem or feature request, open a new issue on Github.

Credits

Author: Florent Champigny

Blog : http://www.tutos-android-france.com/

Fiches Plateau Moto : https://www.fiches-plateau-moto.fr/

Android app on Google Play Follow me on Google+ Follow me on Twitter Follow me on LinkedIn

License

Copyright 2018 florent37, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

inlineactivityresult's People

Contributors

dhaval2404 avatar fleficher avatar florent37 avatar neworld avatar victor-denisenko 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

inlineactivityresult's Issues

Infinite loop when don't keep activities is enabled

Hi 👋

The library doesn't work when the "don't keep activities" is checked in the developer options.
When we start the activity with startForResult (using kotlin coroutines in my case), the desired activity start. But when the user leaves the activity, the activity restarts infinitely and the user needs to kill the app.

Steps to reproduce

You can reproduce this with the sample project.

1- Enable "don't keep activities" in developer options
2- start an activity with startForResult, with a camera intent for example.
3- press back button to leave
4- the camera activity restart again and the user can't go back to the app.

Intent not start for the second time.

Hi.
I'm using your library in a following way.

suspend fun test(){
    val cameraResult = activity.startForResult(cameraIntent)
    val cropResult = activity.startForResult(cropIntent)
}

The second Intent isn't started. I've investigated a bit and found following peace of code

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == REQUEST_CODE) {
            if (listener != null) {
                listener.onActivityResult(requestCode, resultCode, data);
            }
            removeFragment();
        }
    }

So as I understand when I receive result from CAMERA my coroutine tried to start second(crop) Intent. But then you do the following

private void start(@NonNull final Intent intent) {
        final FragmentActivity activity = activityReference.get();
        if (activity == null || activity.isFinishing()) {
            return;
        }

        final ActivityResultFragment oldFragment = (ActivityResultFragment) activity
                .getSupportFragmentManager()
                .findFragmentByTag(TAG);

        if (oldFragment != null) {
            oldFragment.setListener(listener);
        } else {
            final ActivityResultFragment newFragment = ActivityResultFragment.newInstance(intent);
            newFragment.setListener(listener);

            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    activity.getSupportFragmentManager()
                            .beginTransaction()
                            .add(newFragment, TAG)
                            .commitNowAllowingStateLoss();
                }
            });

        }
    }

And as fragment is still exists my second Intent not started.

Create a new release?

I see there was some bug fixes merged in, in the last couple months. But that last release seems to be from November 2019.

No countermeasure for Activity recreation when the screen rotates

I found a trivial bug. rx and coroutine packages are affected by this.

Scenario

  1. A Activity starts B Activity.
  2. Rotate the screen in B Activity.
  3. Tap the back button in B Activity.
  4. A Activity will lost the activity result from B Activity.

Activitys are recreated when the screen rotates as we know. Starting another Activity is also the case. If B Activity has been rotated, then A Activity get recreated.(It's deferred until B Activity is finished) In this case, A Activity calling startActivityForResult() never get callback for onActivityResult(). (It would be called in another instance of A Activity).

I attach a video that actually reproduces the bug.

device-2021-01-15-021348.mp4

Make it work without Activity (but with Context)

Hi, thanks for your library.

Can you add feature for support start activity for result only with context, without activity or fragment? Useful for quickly access to other libraries, that depend on activityForResult behavior.
If you don't mind, I could create a PR with this feature

Where is the class of "com.github.florent37.inlineactivityresult.InlineActivityResult"

Hey @florent37

This repository has caught my eyes because it seems promising in resolving the almost unbearable callback of onActivityResult between activities. So I checked out the master branch of the repository and see how it is implemented behind the scene.

However, I could not find the class com.github.florent37.inlineactivityresult.InlineActivityResult in code base, even though I could find com.github.florent37.inlineactivityresult.rx.RxInlineActivityResult, which is really odd.

Any thoughts?

Best regards,
Tony

AndroidX added registerForActivityResult instead of startActivityForResult

AndroidX has added registerForActivityResult instead of startActivityForResult, which is very powerful, and its purpose should be the same as InlineActivityResult..
AndroidX新增了registerForActivityResult代替startActivityForResult,功能很强大的样子,和InlineActivityResult的目的应该是一样的。

public interface IActivityResult {

    /**
     * @param caller {@link androidx.fragment.app.FragmentActivity} or {@link androidx.fragment.app.Fragment}
     */
    default ActivityResultLauncher<Intent> registerStartActivityForResult(ActivityResultCaller caller, ActivityResultCallback<ActivityResult> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), callback);
    }

    default ActivityResultLauncher<String> registerRequestPermission(ActivityResultCaller caller, ActivityResultCallback<Boolean> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.RequestPermission(), callback);
    }

    default ActivityResultLauncher<String[]> registerRequestMultiplePermissions(ActivityResultCaller caller, ActivityResultCallback<Map<String, Boolean>> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), callback);
    }

    default ActivityResultLauncher<Void> registerTakePicturePreview(ActivityResultCaller caller, ActivityResultCallback<Bitmap> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.TakePicturePreview(), callback);
    }

    default ActivityResultLauncher<Uri> registerTakePicture(ActivityResultCaller caller, ActivityResultCallback<Boolean> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.TakePicture(), callback);
    }

    default ActivityResultLauncher<Uri> registerTakeVideo(ActivityResultCaller caller, ActivityResultCallback<Bitmap> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.TakeVideo(), callback);
    }

    default ActivityResultLauncher<String> registerGetContent(ActivityResultCaller caller, ActivityResultCallback<Uri> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.GetContent(), callback);
    }

    default ActivityResultLauncher<String> registerGetMultipleContents(ActivityResultCaller caller, ActivityResultCallback<List<Uri>> callback) {
        return caller.registerForActivityResult(new ActivityResultContracts.GetMultipleContents(), callback);
    }

    default ActivityResultLauncher<Void> registerAppDetailsSettings(ActivityResultCaller caller, ActivityResultCallback<Void> callback) {
        return caller.registerForActivityResult(new AppDetailsSettings(), callback);
    }

    default ActivityResultLauncher<Void> registerAppNotificationSettings(ActivityResultCaller caller, ActivityResultCallback<Boolean> callback) {
        return caller.registerForActivityResult(new AppNotificationSettings(), callback);
    }

    @RequiresApi(api = Build.VERSION_CODES.R)
    default ActivityResultLauncher<Void> registerAllFilesAccessSettings(ActivityResultCaller caller, ActivityResultCallback<Boolean> callback) {
        return caller.registerForActivityResult(new AllFilesAccessSettings(), callback);
    }

    final class AppDetailsSettings extends ActivityResultContract<Void, Void> {

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, Void input) {
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(Uri.parse("package:" + context.getApplicationContext().getPackageName()));
            if (!(context instanceof Activity)) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            return intent;
        }

        @Override
        public Void parseResult(int resultCode, @Nullable Intent intent) {
            return null;
        }
    }

    final class AppNotificationSettings extends ActivityResultContract<Void, Boolean> {
        private Context context;

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, Void input) {
            this.context = context;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
                intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.getApplicationContext().getPackageName());
                if (!(context instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                return intent;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Intent intent = new Intent("android.settings.APP_NOTIFICATION_SETTINGS");
                intent.putExtra("app_package", context.getApplicationContext().getPackageName());
                intent.putExtra("app_uid", context.getApplicationInfo().uid);
                if (!(context instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                return intent;
            }
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            intent.setData(Uri.parse("package:" + context.getApplicationContext().getPackageName()));
            if (!(context instanceof Activity)) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            return intent;
        }

        @Override
        public Boolean parseResult(int resultCode, @Nullable Intent intent) {
            return NotificationManagerCompat.from(context).areNotificationsEnabled();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.R)
    final class AllFilesAccessSettings extends ActivityResultContract<Void, Boolean> {

        @NonNull
        @Override
        public Intent createIntent(@NonNull Context context, Void input) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
            intent.setData(Uri.parse("package:" + context.getApplicationContext().getPackageName()));
            if (!(context instanceof Activity)) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            return intent;
        }

        @Override
        public Boolean parseResult(int resultCode, @Nullable Intent intent) {
            return Environment.isExternalStorageManager();
        }
    }

}

Intent repeatedly fired

I'm finding that ActivityResultFragment fires its intent over and over again, presumably since it calls startActivityForResult in onResume, and it's paused and later resumed whenever an intent is fired, since that opens another app and puts ours in the background. This makes the library unusable; as soon as the called activity finishes and returns a result to my app, the intent is fired again, and the called activity opens again.

According to the docs, onActivityResult should be called before onResume, in which case the fragment should remove itself before its onResume is called, but that's not what I'm experiencing on Android 7.0 and 9.0.

I don't think it's related, but I'm using the coroutines version.

Parcelable encountered IOException writing serializable object (name = java.lang.RuntimeException)

kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for DispatchedContinuation[DefaultDispatcher, Continuation at com.glm.foodcabinet.activity.bind.BindApFragment$onActivityCreated$3$1.invokeSuspend(BindApFragment.kt:73)@9b7ce0c]. Please read KDoc to 'handleFatalException' method and report this incident to maintainers
at kotlinx.coroutines.DispatchedTask.handleFatalException$kotlinx_coroutines_core(DispatchedTask.kt:93)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:64)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Caused by: java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = java.lang.RuntimeException)
at android.os.Parcel.writeSerializable(Parcel.java:1836)
at com.simple.spiderman.CrashModel.writeToParcel(CrashModel.java:174)
at android.os.Parcel.writeParcelable(Parcel.java:1804)
at android.os.Parcel.writeValue(Parcel.java:1710)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:931)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1593)
at android.os.Bundle.writeToParcel(Bundle.java:1253)
at android.os.Parcel.writeBundle(Parcel.java:1000)
at android.content.Intent.writeToParcel(Intent.java:10520)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:3908)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1716)
at android.app.ContextImpl.startActivity(ContextImpl.java:967)
at android.app.ContextImpl.startActivity(ContextImpl.java:938)
at android.content.ContextWrapper.startActivity(ContextWrapper.java:393)
at com.simple.spiderman.SpiderMan.handleException(SpiderMan.java:44)
at com.simple.spiderman.SpiderMan.uncaughtException(SpiderMan.java:30)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1073)
at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1068)
at kotlinx.coroutines.CoroutineExceptionHandlerImplKt.handleCoroutineExceptionImpl(CoroutineExceptionHandlerImpl.kt:33)
at kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:33)
at kotlinx.coroutines.StandaloneCoroutine.handleJobException(Builders.common.kt:182)
at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:229)
at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:903)
at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:860)
at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:825)
at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:111)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:55)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571) 
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738) 
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678) 
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 
Caused by: java.io.NotSerializableException: com.github.florent37.inlineactivityresult.InlineActivityResult
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
at java.util.ArrayList.writeObject(ArrayList.java:762)
at java.lang.reflect.Method.invoke(Native Method)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:1036)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1552)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
at java.io.ObjectOutputStream.writeObject0(Objec

Make it work with Activity

Hey there,

Can you make this work with Activity? Currently it only works with AppCompatActivity and FragmentActivity.

Thanks.

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.