Caused by: java.lang.IllegalStateException: Activity has been destroyed #850

Closed
shawnlinboy opened this Issue Dec 29, 2015 · 34 comments

Comments

Projects
None yet
10 participants
@shawnlinboy

My Glide version is 3.6.1 and here I got a IllegalStateException.
Should Glide handle this problem internally?

java.lang.RuntimeException: Unable to destroy activity {MY PACKAGE NAME}: java.lang.IllegalStateException: Activity has been destroyed
    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4097)
    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4115)
    at android.app.ActivityThread.access$1400(ActivityThread.java:177)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1620)
    at android.os.Handler.dispatchMessage(Handler.java:111)
    at android.os.Looper.loop(Looper.java:194)
    at android.app.ActivityThread.main(ActivityThread.java:5771)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:799)
Caused by: java.lang.IllegalStateException: Activity has been destroyed
    at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1383)
    at android.app.BackStackRecord.commitInternal(BackStackRecord.java:745)
    at android.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:725)
    at com.bumptech.glide.manager.RequestManagerRetriever.getRequestManagerFragment(SourceFile:159)
    at com.bumptech.glide.manager.RequestManagerFragment.onAttach(SourceFile:117)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:865)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1079)
    at android.app.BackStackRecord.run(BackStackRecord.java:852)
    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1485)
    at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1929)
    at android.app.Fragment.performDestroy(Fragment.java:2279)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1079)
    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1061)
    at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:1930)
    at android.app.Activity.performDestroy(Activity.java:6297)
    at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1151)
    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4084)
    ... 10 more
@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Dec 29, 2015

Collaborator

Something probably needs to be done as it comes up sometimes, but we need a consistent repro to figure out what's going on. Can you consistently repro this? Can you make a mini project that demonstrates? Are you doing anything Glide related in the teardown methods or async task? Or more generally can you share the relevant bits of the code?

Can you please read #795 and #803 to see where we stand around onDestroy, yours it not necessarily a dupe, but those two should give you ideas.

For what I can decipher from the stack: there was a load started earlier (say, onCreate), then finish() was called on the activity destroying everything, but the Glide load still trying to finish. So the problem is that the activity terminated too early. These are just guesses, it would be nice to debug this.

Collaborator

TWiStErRob commented Dec 29, 2015

Something probably needs to be done as it comes up sometimes, but we need a consistent repro to figure out what's going on. Can you consistently repro this? Can you make a mini project that demonstrates? Are you doing anything Glide related in the teardown methods or async task? Or more generally can you share the relevant bits of the code?

Can you please read #795 and #803 to see where we stand around onDestroy, yours it not necessarily a dupe, but those two should give you ideas.

For what I can decipher from the stack: there was a load started earlier (say, onCreate), then finish() was called on the activity destroying everything, but the Glide load still trying to finish. So the problem is that the activity terminated too early. These are just guesses, it would be nice to debug this.

@shawnlinboy

This comment has been minimized.

Show comment
Hide comment
@shawnlinboy

shawnlinboy Dec 29, 2015

Thanks 4 your reply @TWiStErRob .

This Stack trace was reported by my app's built-in User Behavior Collector and I've noticed it because this crash was frequently happened in these days. Actually I have not reproduce the bug by myself till now but it really looks not like a joke.

I think I'll follow your advice to have a try and will provide you with a consistent repro if I need your further help.

Thanks 4 your reply @TWiStErRob .

This Stack trace was reported by my app's built-in User Behavior Collector and I've noticed it because this crash was frequently happened in these days. Actually I have not reproduce the bug by myself till now but it really looks not like a joke.

I think I'll follow your advice to have a try and will provide you with a consistent repro if I need your further help.

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Dec 29, 2015

Collaborator

Please report back even if you found the problem and fixed it, because it may help others in the future.

Collaborator

TWiStErRob commented Dec 29, 2015

Please report back even if you found the problem and fixed it, because it may help others in the future.

@alashow

This comment has been minimized.

Show comment
Hide comment
@alashow

alashow Dec 30, 2015

Contributor

I also saw this exception several times. Usually it causes when activity closes and in the same time recyclerView/listView adapter tries to draw views, which uses glide.

I fixed this with creating glide wrapper.

public static void networkImage(Context context, String imageUrl, ImageView targetView, RequestListener requestListener, Drawable imagePlaceholder) {
        if (context instanceof Activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && ((Activity) context).isDestroyed()) {
                return;
            }
        }

        if (context != null) {
            Logger.d("Loading network image: %s", imageUrl);
            DrawableRequestBuilder requestBuilder = Glide.with(context)
                .load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL);

            if (requestListener != null) {
                requestBuilder.listener(requestListener);
            }

            if (imagePlaceholder != null) {
                requestBuilder.placeholder(imagePlaceholder);
            }

            requestBuilder.into(targetView);
        }
    }

But then, I realized that if I use context from targetView, this exception doesn't throw

public static void networkImage(String imageUrl, ImageView targetView, RequestListener requestListener, Drawable imagePlaceholder) {
        if (targetView != null) {
            Logger.d("Loading network image: %s", imageUrl);
            DrawableRequestBuilder requestBuilder = Glide.with(targetView.getContext())
                .load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL);

            if (requestListener != null) {
                requestBuilder.listener(requestListener);
            }

            if (imagePlaceholder != null) {
                requestBuilder.placeholder(imagePlaceholder);
            }

            requestBuilder.into(targetView);
        }
    }
Contributor

alashow commented Dec 30, 2015

I also saw this exception several times. Usually it causes when activity closes and in the same time recyclerView/listView adapter tries to draw views, which uses glide.

I fixed this with creating glide wrapper.

public static void networkImage(Context context, String imageUrl, ImageView targetView, RequestListener requestListener, Drawable imagePlaceholder) {
        if (context instanceof Activity) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && ((Activity) context).isDestroyed()) {
                return;
            }
        }

        if (context != null) {
            Logger.d("Loading network image: %s", imageUrl);
            DrawableRequestBuilder requestBuilder = Glide.with(context)
                .load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL);

            if (requestListener != null) {
                requestBuilder.listener(requestListener);
            }

            if (imagePlaceholder != null) {
                requestBuilder.placeholder(imagePlaceholder);
            }

            requestBuilder.into(targetView);
        }
    }

But then, I realized that if I use context from targetView, this exception doesn't throw

public static void networkImage(String imageUrl, ImageView targetView, RequestListener requestListener, Drawable imagePlaceholder) {
        if (targetView != null) {
            Logger.d("Loading network image: %s", imageUrl);
            DrawableRequestBuilder requestBuilder = Glide.with(targetView.getContext())
                .load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL);

            if (requestListener != null) {
                requestBuilder.listener(requestListener);
            }

            if (imagePlaceholder != null) {
                requestBuilder.placeholder(imagePlaceholder);
            }

            requestBuilder.into(targetView);
        }
    }
@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Dec 30, 2015

Collaborator

Huh, that getContext is weird. I thought that's the same as the activity. You should remember that automatic resource freeing is only done if you give Fragment or Activity to Glide.

It sounds like we need to clear the adapter (list.setAdapter(null)) in onStop or somewhere relevant to prevent loads starting after teardown of the activity started. This should prevent further bind calls, even if the list is still scrolling when the back button (or similar) is pressed.

Collaborator

TWiStErRob commented Dec 30, 2015

Huh, that getContext is weird. I thought that's the same as the activity. You should remember that automatic resource freeing is only done if you give Fragment or Activity to Glide.

It sounds like we need to clear the adapter (list.setAdapter(null)) in onStop or somewhere relevant to prevent loads starting after teardown of the activity started. This should prevent further bind calls, even if the list is still scrolling when the back button (or similar) is pressed.

@shawnlinboy

This comment has been minimized.

Show comment
Hide comment
@shawnlinboy

shawnlinboy Jan 10, 2016

I'd like to share what I'm trying to do with this problem in these days.

In my app, The scene or usage is: I was trying to load a pic in a fragment, let's call it MyMainFragment, the MyMainFragment's attached activity maintained a AsyncTask object where I was trying to add this fragment inside its onPostExecute() method, and the example code was like:

private class FireUpTask extends AsyncTask<Void, Void,Void> {

        @Override
        protected Void doInBackground(Void... params) {
            handleIntent();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            initFragment();
        }
    }

    private void initFragment() {
        if (!isDestroyed()) {
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.main_container, MyMainFragment.newInstance());
            fragmentTransaction.commitAllowingStateLoss();
        }
    }

I was trying to execute FireUpTask inside Activity's onCreate() method without checking the activity's current state, and maybe this was the murderer of this bug.

I looked up AOSP, and I was wondering if this should be the proper way to update your ui or your fragment on the AsyncTask object. http://androidxref.com/6.0.0_r1/xref/packages/apps/Dialer/src/com/android/dialer/calllog/ClearCallLogDialog.java#74

So maybe I should modify my code like this:

private class FireUpTask extends AsyncTask<Void, Void,Void> {

        @Override
        protected Void doInBackground(Void... params) {
            handleIntent();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (isDestroyed() || isFinishing()) {
                return;
            }
            initFragment();
        }
    }

    private void initFragment() {
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.main_container, MyMainFragment.newInstance());
            fragmentTransaction.commitAllowingStateLoss();
    }

I've pushed this change to my git repository, the result still not been tested but I think this should make sense.

I'd like to share what I'm trying to do with this problem in these days.

In my app, The scene or usage is: I was trying to load a pic in a fragment, let's call it MyMainFragment, the MyMainFragment's attached activity maintained a AsyncTask object where I was trying to add this fragment inside its onPostExecute() method, and the example code was like:

private class FireUpTask extends AsyncTask<Void, Void,Void> {

        @Override
        protected Void doInBackground(Void... params) {
            handleIntent();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            initFragment();
        }
    }

    private void initFragment() {
        if (!isDestroyed()) {
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.main_container, MyMainFragment.newInstance());
            fragmentTransaction.commitAllowingStateLoss();
        }
    }

I was trying to execute FireUpTask inside Activity's onCreate() method without checking the activity's current state, and maybe this was the murderer of this bug.

I looked up AOSP, and I was wondering if this should be the proper way to update your ui or your fragment on the AsyncTask object. http://androidxref.com/6.0.0_r1/xref/packages/apps/Dialer/src/com/android/dialer/calllog/ClearCallLogDialog.java#74

So maybe I should modify my code like this:

private class FireUpTask extends AsyncTask<Void, Void,Void> {

        @Override
        protected Void doInBackground(Void... params) {
            handleIntent();
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (isDestroyed() || isFinishing()) {
                return;
            }
            initFragment();
        }
    }

    private void initFragment() {
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
            fragmentTransaction.add(R.id.main_container, MyMainFragment.newInstance());
            fragmentTransaction.commitAllowingStateLoss();
    }

I've pushed this change to my git repository, the result still not been tested but I think this should make sense.

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Jan 10, 2016

Collaborator

Thanks for the details, that looks reasonable.

You could also leverage AsyncTask.cancel: execute the task in onStart, and cancel in onStop (check the activity life cycle diagram). This way initFragment won't be called if its result is not used. Didn't test this, but sounds logical.

Collaborator

TWiStErRob commented Jan 10, 2016

Thanks for the details, that looks reasonable.

You could also leverage AsyncTask.cancel: execute the task in onStart, and cancel in onStop (check the activity life cycle diagram). This way initFragment won't be called if its result is not used. Didn't test this, but sounds logical.

@TWiStErRob TWiStErRob added wontfix and removed repro-needed labels Jan 11, 2016

@Jayvd

This comment has been minimized.

Show comment
Hide comment
@Jayvd

Jayvd Jan 19, 2016

Is this gonna be fixed in the future release? @TWiStErRob @shawnlinboy . I have one of these random crashes too.

Jayvd commented Jan 19, 2016

Is this gonna be fixed in the future release? @TWiStErRob @shawnlinboy . I have one of these random crashes too.

@shawnlinboy

This comment has been minimized.

Show comment
Hide comment
@shawnlinboy

shawnlinboy Jan 19, 2016

@Jayvd Try to review your code, make sure your entrance of using glide is safe. I've got no idea if Glide will fix this in future release. Looks like we can avoid this by ourself.

@Jayvd Try to review your code, make sure your entrance of using glide is safe. I've got no idea if Glide will fix this in future release. Looks like we can avoid this by ourself.

@Jayvd

This comment has been minimized.

Show comment
Hide comment
@Jayvd

Jayvd Jan 19, 2016

@shawnlinboy Yes we could fix it ourselves, but then our code would pretty damn ugly.

Jayvd commented Jan 19, 2016

@shawnlinboy Yes we could fix it ourselves, but then our code would pretty damn ugly.

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Jan 19, 2016

Collaborator

@Jayvd I think it is just bad practice to swallow everything. There are some cases when you need to figure out a better way of doing things. I hate that my devices live one day on battery and I think this is one example which is a potential for drain. You want to do something that the user doesn't want to and won't ever see, so why bother the CPU/network/I/O usage -> battery drain?

code would pretty damn ugly

From personal experience, sadly, that's when you're entering the real world of Android, and advanced framework usage.

@sjudd what do you think, would it be reasonable to check the condition ourselves?

Collaborator

TWiStErRob commented Jan 19, 2016

@Jayvd I think it is just bad practice to swallow everything. There are some cases when you need to figure out a better way of doing things. I hate that my devices live one day on battery and I think this is one example which is a potential for drain. You want to do something that the user doesn't want to and won't ever see, so why bother the CPU/network/I/O usage -> battery drain?

code would pretty damn ugly

From personal experience, sadly, that's when you're entering the real world of Android, and advanced framework usage.

@sjudd what do you think, would it be reasonable to check the condition ourselves?

@sjudd

This comment has been minimized.

Show comment
Hide comment
@sjudd

sjudd Jan 19, 2016

Member

When the Activity is destroyed, Glide is unable to start a new load (if an application context or fragment context is provided). We can't start a new load because we're unable to obtain a valid Context. We can either silently ignore the request, or we can throw an exception.

Typically this error is a developer error that occurs because someone is misusing AsyncTasks (allowing them to finish after an Activity is destroyed) or otherwise attempting to start loads that will never complete. That said, I think we also found a case where it occurs due to weirdness in the framework or support libraries around nested Fragments.

There is a work around for the nested Fragment case where there is no developer error where you can simply acquire RequestManager early in OnCreate using Glide.with() and pass it around rather than calling Glide.with() for every new load.

I'm still not convinced that we're better off silently not starting a load, given that the common case is a developer error and that a workaround exists.

Member

sjudd commented Jan 19, 2016

When the Activity is destroyed, Glide is unable to start a new load (if an application context or fragment context is provided). We can't start a new load because we're unable to obtain a valid Context. We can either silently ignore the request, or we can throw an exception.

Typically this error is a developer error that occurs because someone is misusing AsyncTasks (allowing them to finish after an Activity is destroyed) or otherwise attempting to start loads that will never complete. That said, I think we also found a case where it occurs due to weirdness in the framework or support libraries around nested Fragments.

There is a work around for the nested Fragment case where there is no developer error where you can simply acquire RequestManager early in OnCreate using Glide.with() and pass it around rather than calling Glide.with() for every new load.

I'm still not convinced that we're better off silently not starting a load, given that the common case is a developer error and that a workaround exists.

@shawnlinboy

This comment has been minimized.

Show comment
Hide comment
@shawnlinboy

shawnlinboy Mar 7, 2016

I'm afraid I have to reopen this issue cuz it was sadly happened again.

java.lang.RuntimeException: Unable to destroy activity {com***date/c***Activity}: java.lang.IllegalStateException: Activity has been destroyed
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4177)
   at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4195)
   at android.app.ActivityThread.-wrap5(ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1614)
   at android.os.Handler.dispatchMessage(Handler.java:111)
   at android.os.Looper.loop(Looper.java:207)
   at android.app.ActivityThread.main(ActivityThread.java:5881)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:918)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.IllegalStateException: Activity has been destroyed
   at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1468)
   at android.app.BackStackRecord.commitInternal(BackStackRecord.java:692)
   at android.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:672)
   at com.bumptech.glide.manager.n.a(SourceFile:159)
   at com.bumptech.glide.manager.RequestManagerFragment.onAttach(SourceFile:117)
   at android.app.Fragment.onAttach(Fragment.java:1391)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:945)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1161)
   at android.app.BackStackRecord.run(BackStackRecord.java:800)
   at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1570)
   at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2015)
   at android.app.Fragment.performDestroy(Fragment.java:2446)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1111)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1161)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1143)
   at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2016)
   at android.app.FragmentController.dispatchDestroy(FragmentController.java:218)
   at android.app.Activity.performDestroy(Activity.java:6535)
   at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1172)
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4164)
... 9 more

I'm afraid I have to reopen this issue cuz it was sadly happened again.

java.lang.RuntimeException: Unable to destroy activity {com***date/c***Activity}: java.lang.IllegalStateException: Activity has been destroyed
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4177)
   at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4195)
   at android.app.ActivityThread.-wrap5(ActivityThread.java)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1614)
   at android.os.Handler.dispatchMessage(Handler.java:111)
   at android.os.Looper.loop(Looper.java:207)
   at android.app.ActivityThread.main(ActivityThread.java:5881)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:918)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
Caused by: java.lang.IllegalStateException: Activity has been destroyed
   at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1468)
   at android.app.BackStackRecord.commitInternal(BackStackRecord.java:692)
   at android.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:672)
   at com.bumptech.glide.manager.n.a(SourceFile:159)
   at com.bumptech.glide.manager.RequestManagerFragment.onAttach(SourceFile:117)
   at android.app.Fragment.onAttach(Fragment.java:1391)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:945)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1161)
   at android.app.BackStackRecord.run(BackStackRecord.java:800)
   at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1570)
   at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2015)
   at android.app.Fragment.performDestroy(Fragment.java:2446)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1111)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1161)
   at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1143)
   at android.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2016)
   at android.app.FragmentController.dispatchDestroy(FragmentController.java:218)
   at android.app.Activity.performDestroy(Activity.java:6535)
   at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1172)
   at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4164)
... 9 more

@shawnlinboy shawnlinboy reopened this Mar 7, 2016

@shawnlinboy

This comment has been minimized.

Show comment
Hide comment
@shawnlinboy

shawnlinboy Mar 7, 2016

@sjudd This error occurs in a high probability while our testers running monkey test, though real users may not encounter this problem, but i still believe that there must be something wrong.

@sjudd This error occurs in a high probability while our testers running monkey test, though real users may not encounter this problem, but i still believe that there must be something wrong.

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Mar 7, 2016

Collaborator

Can you acquire a recording of the monkey to see what's happening? (Logs/screenshots)
Is this the same activity, or another that you may have not fixed up yet?

Collaborator

TWiStErRob commented Mar 7, 2016

Can you acquire a recording of the monkey to see what's happening? (Logs/screenshots)
Is this the same activity, or another that you may have not fixed up yet?

@sonique6784

This comment has been minimized.

Show comment
Hide comment
@sonique6784

sonique6784 May 17, 2016

I do have the same issue. It happens when I moved from fragment support to "native" Fragment

I do have the same issue. It happens when I moved from fragment support to "native" Fragment

@TWiStErRob TWiStErRob added repro-needed and removed wontfix labels May 20, 2016

@Guang1234567

This comment has been minimized.

Show comment
Hide comment
@Guang1234567

Guang1234567 May 27, 2016

Hello @TWiStErRob:

I want to ask you a question, thanks.

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
        RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);   <----  line: 153
        if (current == null) {
            current = pendingRequestManagerFragments.get(fm);
            if (current == null) {
                current = new RequestManagerFragment();
                pendingRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();  <-----  (2)   line:  159
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
Caused by: java.lang.IllegalStateException: Activity has been destroyed
    at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1383)
    at android.app.BackStackRecord.commitInternal(BackStackRecord.java:745)
    at android.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:725)
    at com.bumptech.glide.manager.RequestManagerRetriever.getRequestManagerFragment(SourceFile:159)  <---  (2)
    at com.bumptech.glide.manager.RequestManagerFragment.onAttach(SourceFile:117)  <----- (1)

See (1), RequestManagerFragment instance is already exist!

At this moment, why still run into line: 159? That means fm.findFragmentByTag(FRAGMENT_TAG); in line: 153 return null?

Guang1234567 commented May 27, 2016

Hello @TWiStErRob:

I want to ask you a question, thanks.

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
        RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);   <----  line: 153
        if (current == null) {
            current = pendingRequestManagerFragments.get(fm);
            if (current == null) {
                current = new RequestManagerFragment();
                pendingRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();  <-----  (2)   line:  159
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
            }
        }
        return current;
    }
Caused by: java.lang.IllegalStateException: Activity has been destroyed
    at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1383)
    at android.app.BackStackRecord.commitInternal(BackStackRecord.java:745)
    at android.app.BackStackRecord.commitAllowingStateLoss(BackStackRecord.java:725)
    at com.bumptech.glide.manager.RequestManagerRetriever.getRequestManagerFragment(SourceFile:159)  <---  (2)
    at com.bumptech.glide.manager.RequestManagerFragment.onAttach(SourceFile:117)  <----- (1)

See (1), RequestManagerFragment instance is already exist!

At this moment, why still run into line: 159? That means fm.findFragmentByTag(FRAGMENT_TAG); in line: 153 return null?

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob May 27, 2016

Collaborator

@lihanguang huh interesting. So you're expecting fm to give you this of onAttach. I have two possibilities for you: either the fragment manager only returns already attached fragments (or something even later in their lifecycle), or the fragment manager is the children for that this so this itself is not included there. And looking at the code shows it a third option: the fragment is trying to register itself with the activity's root manager and that exception is caught.

Collaborator

TWiStErRob commented May 27, 2016

@lihanguang huh interesting. So you're expecting fm to give you this of onAttach. I have two possibilities for you: either the fragment manager only returns already attached fragments (or something even later in their lifecycle), or the fragment manager is the children for that this so this itself is not included there. And looking at the code shows it a third option: the fragment is trying to register itself with the activity's root manager and that exception is caught.

@Guang1234567

This comment has been minimized.

Show comment
Hide comment
@Guang1234567

Guang1234567 May 30, 2016

@TWiStErRob

I just see that code that glide dev commit after glide version 3.6.1.

// after version 3.6.1
    private void registerFragmentWithRoot(Activity activity) {
    unregisterFragmentWithRoot();
    rootRequestManagerFragment = RequestManagerRetriever.get()
        .getRequestManagerFragment(activity.getFragmentManager(), null);
    if (rootRequestManagerFragment != this) {
      rootRequestManagerFragment.addChildRequestManagerFragment(this);
    }
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
      registerFragmentWithRoot(activity);
    } catch (IllegalStateException e) {
      // OnAttach can be called after the activity is destroyed, see #497.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Unable to register fragment with root", e);
      }
    }
  }

Q1

Is the patch about #497 and this issue?


Additionly, i think @shawnlinboy 's problem is the quote below while run monkeytest.

either the fragment manager only returns already attached fragments (or something even later in their lifecycle)

Can I avoid the quote above like below? Because commitAllowingStateLoss schedules a commit of this transaction. The commit doesnot happen immediately!

// RequestManagerRetriever.java

RequestManagerFragment getRequestManagerFragment(
      final android.app.FragmentManager fm, android.app.Fragment parentHint) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        fm.executePendingTransactions(); // <-------  add this line......
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

Guang1234567 commented May 30, 2016

@TWiStErRob

I just see that code that glide dev commit after glide version 3.6.1.

// after version 3.6.1
    private void registerFragmentWithRoot(Activity activity) {
    unregisterFragmentWithRoot();
    rootRequestManagerFragment = RequestManagerRetriever.get()
        .getRequestManagerFragment(activity.getFragmentManager(), null);
    if (rootRequestManagerFragment != this) {
      rootRequestManagerFragment.addChildRequestManagerFragment(this);
    }
  }

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
      registerFragmentWithRoot(activity);
    } catch (IllegalStateException e) {
      // OnAttach can be called after the activity is destroyed, see #497.
      if (Log.isLoggable(TAG, Log.WARN)) {
        Log.w(TAG, "Unable to register fragment with root", e);
      }
    }
  }

Q1

Is the patch about #497 and this issue?


Additionly, i think @shawnlinboy 's problem is the quote below while run monkeytest.

either the fragment manager only returns already attached fragments (or something even later in their lifecycle)

Can I avoid the quote above like below? Because commitAllowingStateLoss schedules a commit of this transaction. The commit doesnot happen immediately!

// RequestManagerRetriever.java

RequestManagerFragment getRequestManagerFragment(
      final android.app.FragmentManager fm, android.app.Fragment parentHint) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingRequestManagerFragments.get(fm);
      if (current == null) {
        current = new RequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        fm.executePendingTransactions(); // <-------  add this line......
        handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }
@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob May 30, 2016

Collaborator

That part you quoted is not valid. That was my hypothesis, but it was debunked when I looked at the code.
I'm not sure execute pending would be a good idea. It changes how fragments work. Imagine you are adding some fragments with a normal transaction in onCreate, if we add that line, then a Glide load at the end of onCreate will possibly try to execute the commit of those other fragments as well.

Do you have a consistent repro so you can test the behaviour of this modification?

Collaborator

TWiStErRob commented May 30, 2016

That part you quoted is not valid. That was my hypothesis, but it was debunked when I looked at the code.
I'm not sure execute pending would be a good idea. It changes how fragments work. Imagine you are adding some fragments with a normal transaction in onCreate, if we add that line, then a Glide load at the end of onCreate will possibly try to execute the commit of those other fragments as well.

Do you have a consistent repro so you can test the behaviour of this modification?

@sjudd

This comment has been minimized.

Show comment
Hide comment
@sjudd

sjudd May 30, 2016

Member

You can't use executePendingTransactions, see #117.

Member

sjudd commented May 30, 2016

You can't use executePendingTransactions, see #117.

@rajibhasan11

This comment has been minimized.

Show comment
Hide comment
@rajibhasan11

rajibhasan11 Aug 17, 2016

I also got the similar exception, I think exception will happen if happens any leak in the view (activity, fragment or dialog etc). So need to check that view is not destroyed before to load image from a URL.

rajibhasan11 commented Aug 17, 2016

I also got the similar exception, I think exception will happen if happens any leak in the view (activity, fragment or dialog etc). So need to check that view is not destroyed before to load image from a URL.

@electrolobzik

This comment has been minimized.

Show comment
Hide comment
@electrolobzik

electrolobzik Oct 27, 2016

I have also got this issue when used solution from #1337 for clearing views in fragment's onDestroyView(). I want to describe the source of my issue maybe it will help somebody. This was my code:

private RequestManager imageLoader;

@Override
public void onDestroyView() {
    super.onDestroyView();
    getImageLoader().onDestroy();
}

protected RequestManager getImageLoader() {
    if (imageLoader == null) {
        imageLoader = Glide.with(this);
    }
    return imageLoader;
}

If Glide was used somewhere in the fragment everything worked fine. But if the fragment didn't call getImageLoader() during it's normal work the app crashed during onDestroy(). And this is what happened:

  1. when fragment called getImageLoader() in onDestroyView() Glide tried to create his RequestManagerFragment and attach it to the main fragment.
  2. fragment transaction was queued but not executed
  3. in onDestroy() fragment executed pending transactions and attaches glide's RequestManagerFragment
  4. RequestManagerFragment tries to do it's business and gets this error

So my solution was to avoid creating of RequestManagerFragment in destroy flow of the fragment. I just replaced getImageLoader() with if (imageLoader != null) and the issue gone:

@Override
public void onDestroyView() {
    super.onDestroyView();

    if (imageLoader != null) {
        imageLoader.onDestroy();
    }
}

I suppose that Glide should handle this situation and write error to the LogCat with clear message.

electrolobzik commented Oct 27, 2016

I have also got this issue when used solution from #1337 for clearing views in fragment's onDestroyView(). I want to describe the source of my issue maybe it will help somebody. This was my code:

private RequestManager imageLoader;

@Override
public void onDestroyView() {
    super.onDestroyView();
    getImageLoader().onDestroy();
}

protected RequestManager getImageLoader() {
    if (imageLoader == null) {
        imageLoader = Glide.with(this);
    }
    return imageLoader;
}

If Glide was used somewhere in the fragment everything worked fine. But if the fragment didn't call getImageLoader() during it's normal work the app crashed during onDestroy(). And this is what happened:

  1. when fragment called getImageLoader() in onDestroyView() Glide tried to create his RequestManagerFragment and attach it to the main fragment.
  2. fragment transaction was queued but not executed
  3. in onDestroy() fragment executed pending transactions and attaches glide's RequestManagerFragment
  4. RequestManagerFragment tries to do it's business and gets this error

So my solution was to avoid creating of RequestManagerFragment in destroy flow of the fragment. I just replaced getImageLoader() with if (imageLoader != null) and the issue gone:

@Override
public void onDestroyView() {
    super.onDestroyView();

    if (imageLoader != null) {
        imageLoader.onDestroy();
    }
}

I suppose that Glide should handle this situation and write error to the LogCat with clear message.

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 11, 2016

The above solution is not a fix-all. If you have fragments in a viewpager, the onDestroyView code will kill all of the images in the other fragments in the viewpager when one of them has their view destroyed (by swiping through enough pages to go past the offscreen page limit). Although, if you do this logic in the parent, it might work.

jt-gilkeson commented Nov 11, 2016

The above solution is not a fix-all. If you have fragments in a viewpager, the onDestroyView code will kill all of the images in the other fragments in the viewpager when one of them has their view destroyed (by swiping through enough pages to go past the offscreen page limit). Although, if you do this logic in the parent, it might work.

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Nov 11, 2016

Collaborator

@jt-gilkeson hmm, that's an interesting issue. I think that shouldn't happen if you use the fragment's this on the UI thread. Take a look at RequestManagerRetriever#get(Fragment) and you should see that it uses getChildFragmentManager whenever available. Are you on an old device perhaps with non-support Fragments?

Collaborator

TWiStErRob commented Nov 11, 2016

@jt-gilkeson hmm, that's an interesting issue. I think that shouldn't happen if you use the fragment's this on the UI thread. Take a look at RequestManagerRetriever#get(Fragment) and you should see that it uses getChildFragmentManager whenever available. Are you on an old device perhaps with non-support Fragments?

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 11, 2016

@TWiStErRob That may be my problem, I was using getContext() in the fragment, not "this" (I missed the distinction). Just verified that using "this" does isolate the destroy - my error. Thanks for the follow up and sorry for the confusion.

jt-gilkeson commented Nov 11, 2016

@TWiStErRob That may be my problem, I was using getContext() in the fragment, not "this" (I missed the distinction). Just verified that using "this" does isolate the destroy - my error. Thanks for the follow up and sorry for the confusion.

@alashow

This comment has been minimized.

Show comment
Hide comment
Contributor

alashow commented Nov 11, 2016

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Nov 11, 2016

Collaborator

@jt-gilkeson Yep, if you destroy the activity manager everything loaded with the activity manager is cleared: http://stackoverflow.com/a/32887693 Remember that manually calling onDestroy is not how the API was designed.

Collaborator

TWiStErRob commented Nov 11, 2016

@jt-gilkeson Yep, if you destroy the activity manager everything loaded with the activity manager is cleared: http://stackoverflow.com/a/32887693 Remember that manually calling onDestroy is not how the API was designed.

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 11, 2016

@TWiStErRob I imagine having to do any of this stuff to not crash your app, is not how the API was intended to be designed :)

@TWiStErRob I imagine having to do any of this stuff to not crash your app, is not how the API was intended to be designed :)

@TWiStErRob

This comment has been minimized.

Show comment
Hide comment
@TWiStErRob

TWiStErRob Nov 11, 2016

Collaborator

True that, but #850 (comment). Also this is likely not fixed yet, because there's no consistent repro that is not coming from a weird Glide usage (starting a load after destroy).

Collaborator

TWiStErRob commented Nov 11, 2016

True that, but #850 (comment). Also this is likely not fixed yet, because there's no consistent repro that is not coming from a weird Glide usage (starting a load after destroy).

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 11, 2016

Gotcha, so maybe we don't need any of this cleanup stuff if we would have correctly passed in the fragment's this pointer in the first place? It looks like the original implementation we had was passing in getActivity() (which, when we saw the crash show up, we mistakenly changed to getContext() from the fragment - thinking it would use the fragment). Sorry for all the confusion - when we saw the crash we looked for issues containing the crash and ended up down this path - which now sounds like a red herring, when the real issue for us was not using the right with() param. Thanks for the help - we have multiple people copying/pasting and things get confused easily.

jt-gilkeson commented Nov 11, 2016

Gotcha, so maybe we don't need any of this cleanup stuff if we would have correctly passed in the fragment's this pointer in the first place? It looks like the original implementation we had was passing in getActivity() (which, when we saw the crash show up, we mistakenly changed to getContext() from the fragment - thinking it would use the fragment). Sorry for all the confusion - when we saw the crash we looked for issues containing the crash and ended up down this path - which now sounds like a red herring, when the real issue for us was not using the right with() param. Thanks for the help - we have multiple people copying/pasting and things get confused easily.

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 15, 2016

OK I've got a reproducible instance of the original issue, which may help track down the issue:

We have a tablet layout which in landscape has a fragment with a master / detail layout.

The master fragment (retained instance) has on the left hand side a list of items, and a frame on the right hand side where an embedded fragment gets loaded. If you rotate to portrait, only the master view is shown and clicking on the list selection launches an individual activity.

The landscape detail view can contain a UserReviewsFragment (nested) fragment (if selected in the list) where we are calling:

Glide.with(this).load(pictureUrl).crossFade().into(holder.reviewRowImage);

In the master fragment, we switch the fragment in the detail view via:

    FragmentTransaction ft = mOurChildFragmentManager.beginTransaction();
    ft.replace(R.id.profile_fragment_holder, frag, null);
    ft.commitAllowingStateLoss();

Where frag may be UserReviewsFragment.newInstance(); or another fragment created via newInstance();

If we rotate to portrait (which does not have the detail fragment), then rotate back to landscape, when we try to select the UserReviewsFragment (which has the glide call in it), it crashes with the following:

Fatal Exception: java.lang.IllegalStateException: Activity has been destroyed
       at android.support.v4.app.FragmentManagerImpl.enqueueAction(SourceFile:1515)
       at android.support.v4.app.BackStackRecord.commitInternal(SourceFile:638)
       at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(SourceFile:621)
       at com.bumptech.glide.manager.RequestManagerRetriever.getSupportRequestManagerFragment(SourceFile:187)
       at com.bumptech.glide.manager.SupportRequestManagerFragment.onAttach(SourceFile:116)
       at android.support.v4.app.Fragment.onAttach(SourceFile:1165)
       at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1019)
       at android.support.v4.app.BackStackRecord.setLastIn(SourceFile:779)
       at android.support.v4.app.BackStackRecord.calculateFragments(SourceFile:802)
       at android.support.v4.app.BackStackRecord.run(SourceFile:660)
       at android.support.v4.app.FragmentManagerImpl.execPendingActions(SourceFile:1617)
       at android.support.v4.app.FragmentManagerImpl$1.run(SourceFile:517)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6077)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

The key seems to be rotating, then initializing the nested fragment - if you don't rotate, the fragment uses Glide with no problem. So repro steps: Open the master/detail fragment (UserReviewsFragment doesn't ever have to be created), Rotate to portrait, Rotate back to landscape, click on item to instantiate and show the nested UserReviewsFragment - crash.

PS: The onDestroyView workaround does not work for this, it crashes when a new fragment gets created and mRequestManager.load() gets called.

Note:
Glide.with(this) (fragment) crashes,
Glide.with(getActivity()) crashes,
Glide.with(holder.reviewRowImage.getContext()) crashes,
Glide.with(getContext().getApplicationContext()) works (and appears to be the only way to get this to work)

jt-gilkeson commented Nov 15, 2016

OK I've got a reproducible instance of the original issue, which may help track down the issue:

We have a tablet layout which in landscape has a fragment with a master / detail layout.

The master fragment (retained instance) has on the left hand side a list of items, and a frame on the right hand side where an embedded fragment gets loaded. If you rotate to portrait, only the master view is shown and clicking on the list selection launches an individual activity.

The landscape detail view can contain a UserReviewsFragment (nested) fragment (if selected in the list) where we are calling:

Glide.with(this).load(pictureUrl).crossFade().into(holder.reviewRowImage);

In the master fragment, we switch the fragment in the detail view via:

    FragmentTransaction ft = mOurChildFragmentManager.beginTransaction();
    ft.replace(R.id.profile_fragment_holder, frag, null);
    ft.commitAllowingStateLoss();

Where frag may be UserReviewsFragment.newInstance(); or another fragment created via newInstance();

If we rotate to portrait (which does not have the detail fragment), then rotate back to landscape, when we try to select the UserReviewsFragment (which has the glide call in it), it crashes with the following:

Fatal Exception: java.lang.IllegalStateException: Activity has been destroyed
       at android.support.v4.app.FragmentManagerImpl.enqueueAction(SourceFile:1515)
       at android.support.v4.app.BackStackRecord.commitInternal(SourceFile:638)
       at android.support.v4.app.BackStackRecord.commitAllowingStateLoss(SourceFile:621)
       at com.bumptech.glide.manager.RequestManagerRetriever.getSupportRequestManagerFragment(SourceFile:187)
       at com.bumptech.glide.manager.SupportRequestManagerFragment.onAttach(SourceFile:116)
       at android.support.v4.app.Fragment.onAttach(SourceFile:1165)
       at android.support.v4.app.FragmentManagerImpl.moveToState(SourceFile:1019)
       at android.support.v4.app.BackStackRecord.setLastIn(SourceFile:779)
       at android.support.v4.app.BackStackRecord.calculateFragments(SourceFile:802)
       at android.support.v4.app.BackStackRecord.run(SourceFile:660)
       at android.support.v4.app.FragmentManagerImpl.execPendingActions(SourceFile:1617)
       at android.support.v4.app.FragmentManagerImpl$1.run(SourceFile:517)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6077)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

The key seems to be rotating, then initializing the nested fragment - if you don't rotate, the fragment uses Glide with no problem. So repro steps: Open the master/detail fragment (UserReviewsFragment doesn't ever have to be created), Rotate to portrait, Rotate back to landscape, click on item to instantiate and show the nested UserReviewsFragment - crash.

PS: The onDestroyView workaround does not work for this, it crashes when a new fragment gets created and mRequestManager.load() gets called.

Note:
Glide.with(this) (fragment) crashes,
Glide.with(getActivity()) crashes,
Glide.with(holder.reviewRowImage.getContext()) crashes,
Glide.with(getContext().getApplicationContext()) works (and appears to be the only way to get this to work)

@jt-gilkeson

This comment has been minimized.

Show comment
Hide comment
@jt-gilkeson

jt-gilkeson Nov 17, 2016

I've created a new item for this with a Demo app, since my repro steps are very specific (and I've simplified quite a bit from above)
#1592

jt-gilkeson commented Nov 17, 2016

I've created a new item for this with a Demo app, since my repro steps are very specific (and I've simplified quite a bit from above)
#1592

@sjudd

This comment has been minimized.

Show comment
Hide comment
@sjudd

sjudd Nov 12, 2017

Member

Duplicate of #1592

Member

sjudd commented Nov 12, 2017

Duplicate of #1592

@sjudd sjudd marked this as a duplicate of #1592 Nov 12, 2017

@sjudd sjudd closed this Nov 12, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment