emilsjolander / sprinkles

Sprinkles is a boiler-plate-reduction-library for dealing with databases in android applications
Apache License 2.0
772 stars 84 forks source link

OneQuery.getAsync() returns null when OneQuery.get() doesn't #72

Closed karllindmark closed 10 years ago

karllindmark commented 10 years ago

Hello world!

I'm seeing some strange issues with Sprinkles when using it in my nested Fragments (in a FragmentStatePagerAdapter that I pass getChildFragmentManager() into).

Consider the following code in onViewCreated:

DetailedStatsDAO detailedStatsDAO = Query.one(
    DetailedStatsDAO.class,
        "SELECT * " +
        "FROM " + DetailedStatsDAO.TABLE_NAME + " " +
        "WHERE soldierId = ? AND platformId = ? AND version = ?",
        arguments.getString(Keys.Soldier.ID, ""),
        arguments.getInt(Keys.Soldier.PLATFORM, 0),
        BuildConfig.VERSION_CODE
    ).get();

    Log.d("HelloSprinkles", "[onViewCreated] detailedStatsDAO => " + detailedStatsDAO);
    sendDataToListView(view, detailedStatsDAO.getDetailedStats().getItems());
    showLoadingState(false);

This populates the ListView as expected to, as statsDAO is an instance of DetailedStatsDao:

D/HelloSprinkles﹕ [onViewCreated] detailedStatsDAO => DetailedStatsDAO@43c73408

However, consider the same query and handling of result, but using getAsync() instead:

Query.one(
    DetailedStatsDAO.class,
    "SELECT * " +
    "FROM " + DetailedStatsDAO.TABLE_NAME + " " +
    "WHERE soldierId = ? AND platformId = ? AND version = ?",
    arguments.getString(Keys.Soldier.ID, ""),
    arguments.getInt(Keys.Soldier.PLATFORM, 0),
    BuildConfig.VERSION_CODE
).getAsync(
    getLoaderManager(),
    new OneQuery.ResultHandler<DetailedStatsDAO>() {
        @Override
        public boolean handleResult(DetailedStatsDAO detailedStatsDAO) {
            Log.d("HelloWorld", "[getAsync] detailedStatsDAO => " + detailedStatsDAO);
            if (detailedStatsDAO == null) {
                return true;
            }

            sendDataToListView(view, detailedStatsDAO.getDetailedStats().getItems());
            showLoadingState(false);
            return true;
        }
    }
);

This instead gives me a null value, for some non-apparent reason:

D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => null

If I then swipe to the fragment in question, it gets passed an OK instance upon the fragment sliding into view:

D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => DetailedStatsDAO@449d0808

...and, as an added "whaaaaa...t" bonus, passing getFragmentManager() instead of getChildFragmentManager() in the parent fragment seems to get me the correct results using getAsync:

D/HelloSprinkles﹕ [getAsync] detailedStatsDAO => DetailedStatsDAO@42d58fd8

Any thoughts? I'm not sure I fully understand why things are going down the way they are, as I believe getAsync should be returning the same results as get() does.

Thanks :-)

karllindmark commented 10 years ago

Is it possible that #59 fixes this issue? @emilsjolander @mechinn

emilsjolander commented 10 years ago

yes, it probably does. Wait for 1.3.0 to come out and report back!

karllindmark commented 10 years ago

@emilsjolander: I'll build the jar from the current master branch, to see if #59 solves the problem.

emilsjolander commented 10 years ago

:+1:

mechinn commented 10 years ago

unlikely actually, the restartLoader fix allowed the same async queries to be used over and over again with different variables.

What you're running into an odd thing with android loaders in general if you haven't worked with them before: Loaders normally return null as the data value when the view is being created and destroyed so you need to handle them in your view code whether that means you ignore null and keep your view as is or blank out your view because your loader is telling you there is no data.

http://developer.android.com/guide/components/loaders.html

karllindmark commented 10 years ago

@mechinn: Yeah, they sure act strange a lot of times. I'm currently running 1.2.5-SNAPSHOT with the #59 fix in place, but I'm still seeing the issue at hand.

@emilsjolander figured out that the LoaderManager might not work as expected when nested, as that seemed correct - passing getActivity().getLoaderManager() worked while getLoaderManager() didn't. It seems as if the fragments aren't receiving the callbacks before they are actually displayed, even though the view might have already been created. I'm guessing @emilsjolander might be able to explain that in a better way, haha. :-)

I'll close this issue, as it's more of a matter of Android not delivering the loaders as expected to.