Office Hours — Today, April 21

Yesterday, April 20

Apr 21
7:20 PM
Mark M.
has entered the room
7:25 PM
Mark M.
turned on guest access
7:30 PM
Michaelidle
has entered the room
Mark M.
hello, Michaelidle!
how can I help you today?
7:35 PM
Michaelidle
I've been refactoring my code to try to get the best performance when loading my MainActivity. It's a fairly simple ListView that get's loaded by my custom adapter. The Adapter is backed by a List<Conversations>. I'm creating the List<> on a background thread because I want to load the Conversation objects on a background thread because my conversations are tucked away in a SQLite DB. When my list is rebuilt from the background thread I use an eventbus to let the UI know that the data is ready. This is working fine, but every now and then I get an issue: http://stackoverflow.com/questions/3132021/andr... Is it really a hard rule that I can't update the list from the background. Seems very strange to me that this causes an exception.
7:40 PM
Mark M.
"Is it really a hard rule that I can't update the list from the background" -- yes
however, you should not get that "every now and then", unless you are updating your list along several different code paths
what event bus implementation are you using?
7:45 PM
Michaelidle
I'm using Otto, but I have an interesting scenario going on. I have a ConvoProvider class that tries to implement the Provider pattern. It holds a member variables of List<Conversations>, but when you do ConvoProvider.getList() it internally does return Collections.unmodifiableList(internalList);
Finding it tough working with list in Android to make sure that I'm not hanging the UI, loading from the background, and not modifying the list from multiple threads causing a CME>
Mark M.
you might want to consider switching from Otto to greenrobot's EventBus
then, when you post the HeyWeNeedToUpdateTheListEvent, your UI can subscribe to it specifically on the main application thread
Michaelidle
Well, I have a snippet of code that allows it to update on the main thread. So the event is sent from a Separate thread, and it gets consumed on the main thread, which will either create a new adapter, and set it to the ListView or call notify data set changed on the adapter.
7:50 PM
Michaelidle
So the adapter.notifyDataSetChanged and Listview.setAdapter happens on the main thread, but the actual list is always being created/modified on a background thread.
Mark M.
then you should not be getting that exception
at least for the "created" part
you cannot modify the contents of the list directly held by the ArrayAdapter on a background thread, at least without a corresponding notifyDataSetChanged() on the main application thread
Michaelidle
So the logic is sound... I should be able to create or modify a list on the background... and then when it's done to call notify data set changed.
Mark M.
the catch with the modification comes in if something triggers a UI update while you are doing the modifications
what the exception is telling you is that what the ArrayAdapter thinks is in the list, and what is actually in the list, are two different things
Michaelidle
I'm guessing it has to come down to this answer in the SO question I posted "This illegalStateException arises when a ui thread is updating the view and another background thread changes the data again. That moment causes this issue."
Mark M.
right
which is why I do not modify the list held by the ArrayAdapter on a background thread
Michaelidle
Yeah, I guess that makes sense, but just feels like it could get slow.
Mark M.
you are welcome to do the I/O and other heavy work on the background thread to load the new list contents
Michaelidle
Maybe I'm optimizing prematurely.
7:55 PM
Michaelidle
I'm guessing my issue may come from the fact that my reloading or rebuilding of the list could happen to be called twice in some cases, but every time I rebuild I create a new thread.
Mark M.
that certainly won't help matters, though it would not directly lead to this exception
while I'm no MVC/MVP/MVVM/etc. expert, you might want to think of what the ArrayAdapter holds as being a view-model, independent of the model that you are maintaining on the background thread
only update the view-model on the main application thread
you're free to update the model on background threads
Michaelidle
But it is synchronized. Hm. I will give it another shot. Out of curiosity what do you think of this "Provider class" returning a list via Collections.unmodifiableList(myList); Do you happen to know if it returns a brand new List? If so... then this should be an impossible exception to get.
Mark M.
I haven't used unmodifiableList(), sorry
Michaelidle
Any recommended ways to do this whole paradigm?
Mark M.
well, "this whole paradigm" is kinda broad
Michaelidle
Not trying to reinvent the wheel here.
8:00 PM
Michaelidle
Yeah, it's just loading from the db, into a list<>, putting that into the ArrayAdapter in the ListView.
But your recommendation is to think of the ArrayAdapter as the "View" layer more so than the "Model" layer?
Mark M.
oh, certainly
now, you could argue where in the view/controller or view/presenter dividing line it falls
but it's not the model
Michaelidle
Okay, I will try to refactor my code with those things in mind. Thanks
Mark M.
in the next book update, I'll be covering a TinyTextEditor sample
multiple tabs (and on Android N, multiple windows)
mostly, it is an extended example of using the Storage Access Framework (ACTION_OPEN_DOCUMENT and kin)
related to this discussion, you'll see the general pattern that I use:
1. use a background thread of some form for the I/O (in this case, an IntentService)
2. have the background thread post an event with the result of the data load on a greenrobot EventBus
3. have the UI subscribe to such events on the main application thread
4. have the UI update itself (e.g., populate the EditText)
so far, that basic pattern has been working well for me
8:05 PM
Michaelidle
What's the ETA of that update. Days weeks or months (just so that I keep my eyes peeled)
Mark M.
first week of May
probably Monday, May 2
Michaelidle
Great, Thanks.
8:15 PM
Michaelidle
So another question for the night and then I'm done. I've been doing java for a while, but really haven't gone into multiple threads. It's mostly because my first job had me doing some interesting stuff, including some legacy code, which was a huge single threaded application. So now I'm doing Android and I've got a few threads in the application I'd like to start right when the application starts. For instance... in App.OnCreate() I'd like to create a "forever running thread" that I can just pass in db commands. I don't want the churn of creating a plain old java thread every time I want to do database work (which is basically all the time in my current application). I'm creating, updating, deleting and querying fairly often. Is there a standard way to do this? I have Java Concurrency in Practice sitting on my desk (Just came in on Monday).
Mark M.
I'd use Executors.newSingleThreadExecutor()
this will give you an Executor with a work queue and a single thread monitoring that queu
er, queue
you can then put Runnables on that queue, to have the thread do the work
8:20 PM
Mark M.
and, when there is no work to be done, the thread is blocking on the queue, and so it does not consume CPU time
Michaelidle
That sounds excellent. I'll start that bad boy up in the onCreate and take it from there.
8:25 PM
Michaelidle
Have a good night Mark. Thanks for the advice. Looking forward to that book update!
Mark M.
have a pleasant evening!
8:30 PM
Michaelidle
has left the room
Mark M.
turned off guest access

Yesterday, April 20

 

Office Hours

People in this transcript

  • Mark Murphy
  • Michaelidle