Scenario where initLoader() does not call onLoadFinished()

Showing 1-23 of 23 messages
Scenario where initLoader() does not call onLoadFinished() kaciula 10/7/11 6:29 AM
I have a simple activity with one fragment. The fragment uses a CursorLoader to load some data from a ContentProvider. I just call initLoader() inside onActivityCreated() and I populate the UI in onLoadFinished(). If I switch orientations, everything works as expected (onLoadFinished() is called again).

Now, if I move to a new activity, press BACK to get back to my first activity and then switch orientations, I see that onLoaderReset() is called and then, in onActivityCreated(), although initLoader() is called, onLoadFinished() is never called after that. And as a consequence, my UI shows no data.

After doing some testing, I see that this problem appears only if I use setRetainInstance(true) in my fragment. So what's the deal? And how can I fix this without removing setRetainInstance(true)? Do I have to do something in onLoaderReset()? Do I have to somehow give the loader the new activity as the context?

Thanks.
Re: Scenario where initLoader() does not call onLoadFinished() aleksej 10/9/11 6:08 PM
I have the same issue. It looks like the bug in CurorLoader. Any ideas
of workaround fix for that?
Re: Scenario where initLoader() does not call onLoadFinished() Jeremy Drake 10/10/11 10:47 AM
This sounds suspiciously like the issue I am having
http://groups.google.com/group/android-developers/browse_thread/thread/ca3a0c174d284263

I was able to reproduce the bug with pushing a new activity in my own
app, which uses an AsyncTaskLoader instead of a CursorLoader.

Hopefully somebody familiar with the Fragment/FragmentManager/Loader/
LoaderManager code will reply to one (or both) of these threads with
some additional insight.  I'm planning to enter a bug/issue in the
next day or two if I do not hear anything to the contrary.

You may want to try setting a breakpoint around the time you call
initLoader, and see if the LoaderManager's mDestroyed member is true.
This is what led me to believe that the issue is with the lifetime
management of the loader manager.
Re: Scenario where initLoader() does not call onLoadFinished() kaciula 10/11/11 2:57 AM
Indeed, the loader manager destroy() method is called and the field mDestroyed is set to true. After this, the loader manager is not functional anymore. In onLoadComplete() it exits if mDestroyed is set to true. So i guess the problem is that the loader manager for that fragment is destroyed but our fragment is still alive. I would venture to say that this is a bug.

It would be helpful if we find a workaround. I have a big app with a lot of fragments using loaders. For some, I removed setRetainInstance(true) but for others I must use setRetainInstance(true).
Re: Scenario where initLoader() does not call onLoadFinished() kaciula 10/11/11 4:53 AM
I noticed that this problem doesn't appear if I use a ListFragment with a CursorLoader/AsyncTaskLoader and setRetainInstance(true). It only happens when I use a basic Fragment with CursorLoader/AsyncTaskLoader and setRetainInstance(true).
Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Mark Murphy 10/11/11 5:09 AM
If anyone on this thread who is experiencing this problem can cook up
a simple example exhibiting the behavior and upload it somewhere, I'd
be interested to take a peek at it.

Thanks!

--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
http://commonsware.com/blog | http://twitter.com/commonsguy

Android Training...At Your Office: http://commonsware.com/training

Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() kaciula 10/11/11 8:34 AM
Here you go: https://github.com/kaciula/BugRetain

It uses a CursorLoader to take 2 values from a database through a content provider and shows them on screen. Press the button to move to a second activity, then press BACK and then switch orientation of device. The values from db are no longer showing.

PS: I am eagerly awaiting a thorough chapter for loaders in your books :)
Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Mark Murphy 10/11/11 1:41 PM
On Tue, Oct 11, 2011 at 11:34 AM, kaciula <catalin...@gmail.com> wrote:
> Here you go: https://github.com/kaciula/BugRetain
> It uses a CursorLoader to take 2 values from a database through a content
> provider and shows them on screen. Press the button to move to a second
> activity, then press BACK and then switch orientation of device. The values
> from db are no longer showing.

OK. It may take a few days before I get a chance to look at this,
given my travel schedule and other commitments.

> PS: I am eagerly awaiting a thorough chapter for loaders in your books :)

I don't know how much constitutes "thorough" but I have a loader
chapter coming in the next edition of _The Busy Coder's Guide to
Advanced Android Development_. Since I think we will remain Ice Cream
Sandwich-less this week, I hope to publish this update on Monday. I
want to examine your issue before I do that, though, as there's
probably something I should be adding to the chapter, either the
solution for the problem, or a warning to others about the problem.

Thanks for posting the sample!

--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
http://commonsware.com/blog | http://twitter.com/commonsguy

Android 3.1 Programming Books: http://commonsware.com/books

Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Mark Murphy 10/14/11 7:01 AM
On Tue, Oct 11, 2011 at 11:34 AM, kaciula <catalin...@gmail.com> wrote:
> Here you go: https://github.com/kaciula/BugRetain
> It uses a CursorLoader to take 2 values from a database through a content
> provider and shows them on screen. Press the button to move to a second
> activity, then press BACK and then switch orientation of device. The values
> from db are no longer showing.

I can definitely reproduce the problem. It feels like a bug with the
Android Compatibility Library. If I switch your sample to use API
Level 11 and the built-in fragment implementation, it works
successfully, at least in the emulator.

One icky workaround: use android:configChanges.

I have filed an issue on this:
http://code.google.com/p/android/issues/detail?id=20791

--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
http://commonsware.com/blog | http://twitter.com/commonsguy

_The Busy Coder's Guide to Android Development_ Version 3.6 Available!

Re: Scenario where initLoader() does not call onLoadFinished() Jeremy Drake 10/14/11 12:40 PM
On Oct 14, 7:01 am, Mark Murphy <mmur...@commonsware.com> wrote:
> I can definitely reproduce the problem. It feels like a bug with the
> Android Compatibility Library. If I switch your sample to use API
> Level 11 and the built-in fragment implementation, it works
> successfully, at least in the emulator.

That's very interesting.  In the incarnation I am experiencing (with
tabs rather than pushing/popping an activity), I tried modifying the
ApiDemos sample from the 3.2 samples, and still experienced the issue
on a 3.2.1 device (Asus EeePad Transformer).  The post about this was
http://groups.google.com/group/android-developers/browse_thread/thread/ca3a0c174d284263

Now I just need to decide whether to enter this as a new issue, or
just add a comment to yours...
Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() kaciula 10/17/11 2:27 AM
However, if I compile it using API Level 7 but run it on a tablet emulator I still can reproduce the problem. I thought that if you used the acl, when running on a honeycomb device, the built-in fragment implementation would be used. But I see that this is not the case here.

Regarding the configChanges workaround, what exactly are the problems that appear? Except for adding android:configChanges="keyboardHidden|orientation|keyboard|screenLayout", is there something else I should modify?
Re: Scenario where initLoader() does not call onLoadFinished() kaciula 10/24/11 5:46 AM
The new revision (rev. 4) of android support package fixes these issues.
Re: Scenario where initLoader() does not call onLoadFinished() aleksej 10/24/11 4:02 PM
I can't see this was fixed in rev.4, actually. But workaround using
android:configChanges suggested by Mark did the job pretty well for
me.
Re: Scenario where initLoader() does not call onLoadFinished() kaciula 11/4/11 4:08 AM
It turns out that the new revision fixed part of the problem but the bug still remains in some cases.

If you take the code I posted and run it, press the button to launch the new activity, switch orientations only once and then press BACK, it shows the wrong value. The idea is to press BACK from the second activity while it's in a different orientation than the initial activity (if that makes sense). For example, activity A is in portrait, press button, switch orientation of activity B to landscape, press BACK and then enjoy the bug.

Looking more deeply at this, it seems that the problem appears only if onLoaderReset() is called. So, if onLoaderReset() is called, subsequent calls to initLoader() launches/reconnects the loader but onLoadFinished() is never again called.
Re: Scenario where initLoader() does not call onLoadFinished() kaciula 12/12/11 11:29 PM
As I said, the initial bugs were fixed by revision 4 of ACL. However, there is still a bug present in both the ACL and Android. I've tested it with Android version 3.2 and 4.0. Check out the updated project at https://github.com/kaciula/BugRetain

I think this is a pretty important bug. The scenario is this: From activity A, go to activity B, switch once the orientation and go back to activity A. As a consequence of this bug, I can't write an app with fragments that use setRetainInstance and is available in both orientations. I really need a workaround until the Android guys fix the issue. Thoughts?
Re: Scenario where initLoader() does not call onLoadFinished() David Wu 1/12/12 10:47 PM
Hi there,

I ran into a very similar problem and solved it by replacing the
following line in onActivityCreate()

    getLoaderManager().initLoader(0, getArguments(), this);

to

    Loader loader = getLoaderManager().getLoader(0);
    if ( loader != null && loader.isReset() ) {
        getLoaderManager().restartLoader(0, getArguments(), this);
    } else {
        getLoaderManager().initLoader(0, getArguments(), this);
    }


Not sure if it addresses your problem.  I hope it helps.


On Dec 13 2011, 3:29 pm, kaciula <catalin.moro...@gmail.com> wrote:
> As I said, the initial bugs were fixed by revision 4 of ACL. However, there
> is still a bug present in both the ACL and Android. I've tested it with
> Android version 3.2 and 4.0. Check out the updated project athttps://github.com/kaciula/BugRetain
Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Dianne Hackborn 1/12/12 11:54 PM
Hi, we'll look at this issue, but I would generally recommend -- don't use setRetainInstance() with loaders.  It is kind-of weird to do that.  One of the big points of loaders is to take care of propagating state across activity/fragment instances, so there is no need to retain the instance.

On Mon, Dec 12, 2011 at 11:29 PM, kaciula <catalin...@gmail.com> wrote:
As I said, the initial bugs were fixed by revision 4 of ACL. However, there is still a bug present in both the ACL and Android. I've tested it with Android version 3.2 and 4.0. Check out the updated project at https://github.com/kaciula/BugRetain

I think this is a pretty important bug. The scenario is this: From activity A, go to activity B, switch once the orientation and go back to activity A. As a consequence of this bug, I can't write an app with fragments that use setRetainInstance and is available in both orientations. I really need a workaround until the Android guys fix the issue. Thoughts?

--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-d...@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en



--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support, and so won't reply to such e-mails.  All such questions should be posted on public forums, where I and others can see and answer them.

Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Oleg Vaskevich 5/18/12 9:55 PM
Until this is fixed (even without setRetainInstance()), my temporary workaround is:

Put the following into a subclass of the AsyncTaskLoader:

public static final SparseArray<Object> loaderResults = new SparseArray<Object>(); 
 
 ... 
 
public void deliverResult(Object data) {
    loaderResults.put(getId(), data);
  
 ...

And then in your Fragment, put in something like this for onStart():

    @Override
    public void onStart() {
        super.onStart();
        // Get any results that were not sent due to a bug with loaders
        // and send them manually
        SparseArray<Object> rArray = AbstractTaskLoader.loaderResults;
        for (int i = 0; i < rArray.size(); ++i) {
            int loaderId = rArray.keyAt(i);
            // any code that you put in onLoadFinished() here, i.e. dismissing dialog
            rArray.removeAt(i);
        }
    }

And also in onLoadFinished() don't forget to delete() that loader's key from this sparse array to prevent unneeded memory from being GCed.

Hope this helps someone.
Re: Scenario where initLoader() does not call onLoadFinished() Etienne 7/26/12 3:00 PM
Actually it should be:

Loader loader = getLoaderManager().getLoader(-1);
   
if (loader != null && !loader.isReset()) {
      getLoaderManager
().restartLoader(-1, null, this);
   
} else {
      getLoaderManager
().initLoader(-1, null, this);
   
}

You should only restart the loader if the loader is NOT reset.  So the second condition in the if condition changes to the negated version.  I got this to work for me.
Re: [android-developers] Re: Scenario where initLoader() does not call onLoadFinished() Sorenchr 10/3/12 3:17 PM
Are there any updates on this issue? I feel like we should have heard something since your last reply from January.
Re: Scenario where initLoader() does not call onLoadFinished() Rainer 7/4/13 11:16 AM
Etienne, your solution is "nearly" correct. This is the working solution

public static <T> void initLoader(final int loaderId, final Bundle args, final LoaderCallbacks<T> callbacks,
        final LoaderManager loaderManager) {
    final Loader<T> loader = loaderManager.getLoader(loaderId);
    if (loader != null && loader.isReset()) {
        loaderManager.restartLoader(loaderId, args, callbacks);
    } else {
        loaderManager.initLoader(loaderId, args, callbacks);
    }
}
Re: Scenario where initLoader() does not call onLoadFinished() Tobias Fuss 1/11/15 8:28 AM
Hello Rainer, 
currently struggling with the same issue and already tried nearly every possible solution out there (besides using the SupportLoaderManager)
Your solution does not work in my case, after configuration change i still get no onLoadFinished-callback and therefore the data-field stays empty. 
.
I'm using an activity with a single fragment that contains all the loader-stuff in onActivityCreated (also tried this in other lifecycle methods), any other solutions found in the meantime? (API 21, Lollipop)
Thanks in advance
Re: Scenario where initLoader() does not call onLoadFinished() Rainer 1/11/15 9:09 AM
Hi Tobias

I don't know enough about your specific problem, but I can only tell you that the solution that I documented further up is in use in my production applications without problem. The main difference I guess is that I do all loader stuff inside the fragments (i.e. the initloader code is triggered typically from MyFragment.onCreate()).

maybe you provide a few more details which would make it easier to help.

cheers
- Rainer
More topics »