5

Well it seems I'm stuck again. I have my widget half working and I think I know why it's failing but I have no idea how to fix it.

In my widget service class, in the onDataSetChanged() method I make a call to get my data (asynchronously). But the system makes a call to getCount() before the data is loaded and therefore returns 0 for the size and never calls getViewAt().

If I create some fake data inside onDataSetChanged() instead of calling to get the real data from Firebase then it will display just fine. So I know it works apart from this.

I've tried all sorts of things to get it to work but no luck. I don't want to make this into a really long question so I'll try to keep it simple. My question is how does the system know when the data is ready? There doesn't seem to be a method I can call to notify it that the data is now there.

I could be totally wrong but I think that's what the problem is. The onDataSetChanged() method doesn't wait and I have no way to tell it to.

What makes this more confusing is that in my mockDebug version of the app where I use fake static data it actually works, even with the asynchronous call. My conclusion is that it must be loading so fast that it's ready by the time getCount() is called. But even more confusing is that for a short while it was also working in the prodDebug version and then didn't and hasn't ever since. As far as I know I hadn't changed anything in that time. In any case this is the only explanation I've been able to come up with. The reason is because I can see either with the debugger or logging that getCount() is called before the data is loaded when I get the data from Firebase, causing it to fail, but it's called after the data is loaded if I use static data, allowing it to succeed.

How do I make it wait? Or is there something else I may be doing wrong?

Thanks.

Michael Vescovo
  • 3,741
  • 4
  • 32
  • 45

2 Answers2

1

Ok, solution number 2: convert the asynchronous calls into a synchronous call with CountDownLatch.

With this I can get all the data from inside onDataSetChanged() as I was originally trying to with just a couple extra lines of code.

So far I've been able to populate the widget list and also add data to it.

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html

Sync version of async method

Community
  • 1
  • 1
Michael Vescovo
  • 3,741
  • 4
  • 32
  • 45
0

Ok so I accepted that I can't do this asynchronously and moved the code in the ItemWidgetProvider.onUpdate() method to a new IntentService. I replaced the code with a call to start the service with the appWidgetIds as an Intent extra.

In this new IntentService I first retrieve all the data, and then call the code that was previously getting called from onUpdate().


There was one issue I encountered with this solution and that's that for whatever reason (please comment if you know), when I try to pass a Serializable object from the IntentService to the WidgetListService it just won't work. I've created a test Serializable with just a String and even that doesn't work. Same thing with Parcelable. To get around that I convert to a byte[] and send that instead. That works. This is the only time I've ever had this problem and I'm saving the same object to onSaveInstanceState using Serializable and it works fine. Not sure why only in the widget it has a problem.

Edit: this doesn't work. I can get the data in there but there doesn't seem to be a way to update the widget, so it's only good for static widgets.

Michael Vescovo
  • 3,741
  • 4
  • 32
  • 45
  • simply convert the object you want to pass through the intent to JSON object using GSON, as Parcelable and Serialiable objects act unexpectedly with no logical reason sometimes – aya salama Aug 24 '17 at 19:01
  • Yeah that might be an alternative to a byte[] but I couldn't use this solution anyway. Thanks for the idea. – Michael Vescovo Aug 24 '17 at 21:36