Jul 8 | 7:20 PM |
Mark M. | has entered the room |
Mark M. | turned on guest access |
Jul 8 | 7:30 PM |
EGHDK | has entered the room |
Mark M. |
hello, EGHDK
|
Mark M. |
how can I help you today?
|
EGHDK |
Hey Mark. So I finally got to Threads in my java book. So now I have a few questions regarding them and how to use them in Android.
|
EGHDK |
So my first question is... why are there seemingly two ways to start a new thread?
|
Mark M. |
could you be more specific?
|
EGHDK |
Thread can be extended, and then override the run method... or create a thread and pass in a runnable.
|
Mark M. |
the default implementation of run() on Thread presumably just delegates to the supplied Runnable
|
Mark M. |
this allows you use composition (a Thread holds a Runnable) or inheritance (a Thread knows how to run itself) to provide the actual guts of what the thread does
|
Mark M. |
but, beyond that, you'd have to ask the authors of Java
|
EGHDK |
Interesting.
|
EGHDK |
Is anyway better than another?
|
Jeff G. | has entered the room |
Mark M. |
(hello, Jeff -- I'll be with you in a moment!)
|
EGHDK |
lately all I've been doing is new Thread(new Runnable() //overide run method)).start()
|
Jeff G. |
ok.
|
Mark M. |
EGHDK: that's a matter of personal preference
|
EGHDK |
But I saw that I could just make a class of Thread and override run() in Thread... Okay. I guess I'm just looking too far into it.
|
Jul 8 | 7:35 PM |
Mark M. |
let me take a question from Jeff, and I'll be back with you in a bit
|
Jul 8 | 7:35 PM |
Mark M. |
Jeff: your turn! do you have a question?
|
Jeff G. |
Yes.
|
Jeff G. |
I wanted to know if there is a way to use Manifest Merger (or perhaps something else) to selectively choose intents to use from an included library or from the main project itself. perhaps based on category?
|
Mark M. |
I haven't delved too deeply into it
|
Mark M. |
my guess is probably not
|
Jeff G. |
as an alternative, is there a runtime way to selectively choose between intents?
|
Mark M. |
could you explain a bit more about what you mean?
|
Jeff G. |
Well, I'm trying to place a bunch of "reusable" stuff in a library that can be used by multiple projects, but sometimes I want the projects to override the default behavior placed in the library.
|
Jeff G. |
So, for example, if the project handles an intent, I don't want the library to cause the chooser dialog to pop up for a given intent. I just want the end project to handle it.
|
Mark M. |
ah, I see
|
Mark M. |
that I think you can accomplish
|
Jul 8 | 7:40 PM |
Jeff G. |
what is the best method?
|
Mark M. |
best? heck, I'm glad I can come up with one method :-)
|
Mark M. | |
Mark M. |
see the "Element markers examples" section
|
Jeff G. |
I think I read that before (have to check again it's been awhile). It would be cool if I could use the markers for categories.
|
Mark M. |
that may not be possible
|
Mark M. |
in fact, I suspect that you may need to wipe out all <intent-filter> elements for a particular activity in the library that you are overriding
|
Mark M. |
but, again, I haven't played with this in any depth yet
|
Jeff G. |
ok. perhaps there is a different way to get those things imported into my project as defaults.
|
Mark M. |
and it'd be high on my list, if it weren't for migrating a whole book to Android Studio :-)
|
Jeff G. |
ahh, yes.
|
Jeff G. |
good luck with that. i hope it will be included in my existing subscription! :)
|
Mark M. |
so long as it runs through early September, yes
|
Mark M. |
let me swing back to EGHDK, and I'll come back to you in a bit
|
Jeff G. |
I guess I should stop looking for typos in the old version. :)
|
Jeff G. |
no prob. thanks.
|
Mark M. |
EGHDK: your turn! do you have another question?
|
EGHDK |
Okay, so... Thread is a class, and Runnable is an interface... correct?
|
Mark M. |
correct
|
EGHDK |
The only method Runnable has is run... so why would you use a Runnable... except for a new Thread?
|
Mark M. |
well, Android uses it in various other places, like post(), postDelayed(), runOnUiThread(), etc.
|
Jul 8 | 7:45 PM |
Mark M. |
in the world before Java 8, it's the classic way of bundling up a chunk of semi-arbitrary code into an object that can be passed around
|
Jul 8 | 7:45 PM |
EGHDK |
Hmm... okay. So it's not used exclusively for new Thread(Runnable run)
|
Mark M. |
correct
|
Mark M. |
there's probably places in standard Java other than Thread that take a Runnable, though my brain is somewhat fuzzy at the moment and I'm not thinking of any
|
Mark M. |
OK, since we seem to have hit a lull, let me switch back to Jeff, and I'll return to you in a bit
|
Mark M. |
Jeff: do you have another question?
|
Jeff G. |
Yes.
|
Jeff G. |
I've got a listview with data rows that have a lot of textview items. This is more or less a design issue, so it may not be the right venue to ask this. But I'd like to know how to best align textviews so they look "clean."
|
Mark M. |
align them with respect to what?
|
Jeff G. |
I use relative layouts now but I'm thinking some of the stuff should be "right-aligned" just to look good.
|
Jul 8 | 7:50 PM |
EGHDK |
Okay, so this brings me to my main question. I have a method I came up with called fetchContacts() in my ContactManager class. It runs fine on most of my devices... but on devices like the moto g, and say 8k contacts the method takes about 3 seconds to run and it hangs the UI. From what I can see, the GC slows things down, because in logcat it looks like GC gets called like 4 times. I initially just put my fetchContacts() method call in new Thread(new Runnable() @override run(){fetchContacts()}).start(). Then I got the error "Can't create handler inside thread that has not called Looper.prepare()" Now... I
|
Mark M. |
um, why not right-align them using your RelativeLayout?
|
Jeff G. |
well, some stuff is left aligned in the cell, but anything to the right just looks oddly placed.
|
EGHDK |
Sorry, typing up my question didn't mean to hit enter
|
Jeff G. |
how to you right-align?
|
Micalet | has entered the room |
Mark M. |
android:layout_alignParentRight="true"
|
Micalet |
Hello
|
Jeff G. |
right now the "second column" of stuff is just "right-of" the stuff left of it. I would like a way to tell it to right justify to the other side of the cell.
|
Mark M. |
(hello, Micalet -- I will be with you shortly!)
|
Jeff G. |
got it. thanks.
|
Jeff G. |
that's all I have for today. Thanks again.
|
Micalet |
ok
|
Mark M. |
Jeff: OK
|
Mark M. |
Micalet: do you have a question?
|
Micalet |
Yes
|
Micalet |
I have a problem when I try to populate a listview with pictures from internet
|
Micalet |
I have a listview with some textviews and one imageview
|
Micalet |
I populate the listview with info from a sqlite
|
Micalet |
in this database i have the url of some pictures
|
Micalet |
can you take a look at this: http://stackoverflow.com/questions/23896110/sys...
|
Micalet |
?
|
Mark M. |
off the cuff, I would think you need to ask that of the author of that library
|
Jul 8 | 7:55 PM |
Mark M. |
I have no way of telling you why that library is logging those messages and is having a problem
|
Mark M. |
you'll need the INTERNET permission in your manifest, and of course you'll want to check and confirm that the URLs are actually valid
|
Micalet |
I tried to contact with him, but have no answer
|
Mark M. |
maybe the solution is to switch to a different library
|
Micalet |
if you read the comment in this question, I tried other methods with the same result
|
Mark M. |
I use Picasso mostly, with SmartImageView for the use cases where Picasso does not fit
|
Mark M. |
my Internet chapter has a complete example of using Picasso to load images from URLs into rows of a ListView
|
Mark M. |
and my MapsV2 chapter has a complete example of using Picasso to load images from URLs into info windows
|
Micalet |
ok thank you
|
Mark M. |
EGHDK: back to you
|
Micalet |
I'll take a look
|
EGHDK |
Okay, so this brings me to my main question. I have a method I came up with called fetchContacts() in my ContactManager class. It runs fine on most of my devices... but on devices like the moto g, and say 8k contacts the method takes about 3 seconds to run and it hangs the UI. From what I can see, the GC slows things down, because in logcat it looks like GC gets called like 4 times. I initially just put my fetchContacts() method call in new Thread(new Runnable() @override run(){fetchContacts()}).start(). Then I got the error "Can't create handler inside thread that has not called Looper.prepare()" Now... I have come across this problem before in my code in AsyncTask trying to touch a GUI element. I know that I shouldn't touch GUI elements not in the main thread. But so what is this whole deal with Handler and looper and such. From what I can see in my code, I'm not touching GUI elements.
|
Mark M. |
I have no idea what is in your fetchContacts() method, but it is doing something that is normally done on the main application thread
|
Mark M. |
you know exactly what it is, because it's where the stack trace tells you
|
Mark M. |
whatever that is, ponder whether it is something you really want to be doing in the background
|
EGHDK |
Yeah... well erm. That's what I'm trying to figure out.
|
Mark M. |
there are ways to have a thread with a Looper
|
Mark M. |
and so it's entirely possible that this would be the right solution
|
Mark M. |
but until you determine what it is that is triggering this need, nobody can really help you determine what the right course of action is
|
EGHDK |
I'm trying to figur eout of that message "Can't create handler inside thread..." means "DO THIS ON THE MAIN THREAD"
|
Jul 8 | 8:00 PM |
EGHDK |
figure out if*
|
Mark M. |
it's more that it's expected that the work would be done on the main thread, which already has a Looper
|
Mark M. |
that's not to say the work cannot be done in the background, but it does beg the question of whether that bit of the work *should* be done in the background
|
EGHDK |
This may be stemming from the fact that I don't know what a Looper is.
|
EGHDK |
Or Handler.
|
Mark M. |
did you read the book chapter on threading?
|
Mark M. |
(my book, not your Java book)
|
EGHDK |
Your book? No.
|
Mark M. |
no offense, but that might be a good idea
|
EGHDK |
Alright.
|
Mark M. |
I don't write this stuff just for grins :-)
|
EGHDK |
That goes through Looper and such?
|
Mark M. |
it goes through Handler
|
Mark M. |
and uses of Handler
|
Mark M. |
Looper is part of the underpinnings behind Handler and the work queue that the main application thread uses
|
EGHDK |
I actually am putting off picking your book back up until I read my head first java book, head first design book, and effective java. Then I'm going to pick your book back up. And hopefully its after the big pivot.
|
EGHDK |
But I guess I will read this part since it applies to me now.
|
Mark M. |
yeah, if you're trying to do active development in parallel with reading those things cover-to-cover, it'll be a while before you get back to my book
|
EGHDK |
Again, I understood that most likely my code needs to run on the main thread, but I don't get why the error says Looper.prepare().
|
Mark M. |
well, because that's how they elected to word the error message
|
Mark M. |
don't assume that all error messages are well-written
|
EGHDK |
Heh.
|
Jul 8 | 8:05 PM |
Mark M. |
moreover, I think that the authors of that error message expected it to be infrequently encountered by run-of-the-mill app developers
|
Mark M. |
and more encountered by people who are intentionally messing with funky threading stuff
|
Mark M. |
in reality, it shows up more often than they might have thought
|
EGHDK |
So if my new thread(new Runnable(run fetchContacts()).start() code crashes. Why does it not crash when I put Looper.prepare() right before the fetchContacts() method?
|
Mark M. |
well, first, that'd be the wrong place for it
|
Mark M. |
or, more accurately, it's probably insufficient
|
Mark M. |
just having Looper.prepare() is akin to attempting to fry some chicken with just a frying pan, leaving out the stove, oil, and chicken
|
Mark M. |
the point behind a thread with a Looper is for the Looper to be driving what the thread is doing
|
Mark M. |
a concept that would be vastly easier to explain if you read my chapter on threading for background
|
EGHDK |
Okay, so just putting Looper.prepare() doesn't actually do anything?
|
Mark M. |
not in a way that would really address your problem
|
EGHDK |
Okay, I'll read it tonight. Thanks
|
Mark M. |
Micalet: do you have another question?
|
Micalet |
No. Thats all for the moment
|
Mark M. |
OK
|
Mark M. |
if anyone has another question, go right ahead
|
Micalet |
T'll try one of these libraries
|
Micalet | has left the room |
Jul 8 | 8:10 PM |
EGHDK |
Okay, Mark so I set up my contentObserver for seeing when contacts have changed.
|
Mark M. |
OK
|
EGHDK |
It works pretty well. But I was wondering if the contentobserver will be called if my application is in the background... or if my app process is dead.
|
Mark M. |
it will be called while it is registered and your process is running
|
Mark M. |
it will not be called if your app process is dead
|
Mark M. |
because it no longer exists
|
EGHDK |
Okay. So even if my app is in the background but the process is technically running?
|
Mark M. |
it should, so long as the observer is still registered
|
EGHDK |
Got it.
|
EGHDK |
I'm having a problem with GCM.
|
Mark M. |
could you be more specific? :-)
|
Jul 8 | 8:15 PM |
EGHDK |
Basically I have an basic messager app. I create an account "UserA". Then I uninstall the app. Then I install the app again, and create an account "UserB". If someone sends a message to "UserA" the notification now shows up on my phone.
|
EGHDK |
So my problem is unregistering the GCM
|
EGHDK |
I guess.
|
Mark M. |
:: shrug ::
|
Mark M. |
your server should be notified when you attempt to send a message to a GCM ID that has been unregistered
|
Mark M. |
however, that will take some time
|
Mark M. |
if you're trying this test over a matter of minutes, I would not be shocked to see the behavior that you describe
|
EGHDK |
So uninstalling an application "unregisters" the GCM?
|
Mark M. |
it's supposed to -- Play Services detects the uninstall and alerts its GCM servers
|
Mark M. | |
EGHDK |
Okay, so my next part to this question is now, if I have a button in my app for "logging out and delete all user data" almost like an app reset. I should at this time call unregister()?
|
Mark M. |
off the cuff, that seems reasonable
|
Mark M. |
but, I don't know your app well enough to state that conclusively
|
Jul 8 | 8:20 PM |
EGHDK |
Agreed. Okay, so what if I already have devices that already have this problem? Getting duplicate gcm recievers. So its like this one hardware device has two different GCM ids. Is there any way to push out an update, that will just "unregister all the gcms for this app on this phone"?
|
Mark M. |
not that I am aware of
|
EGHDK |
Basically, since unregister() doesn't take a param... how does it know what to unregister?
|
Mark M. |
but you're the one sending to those GCM IDs
|
Mark M. |
GCM caches the ID in your internal storage IIRC
|
Mark M. |
so it knows the ID
|
Mark M. |
if you want your server to stop sending to those GCM IDs, update your server
|
Mark M. |
the "app unregistered" path is designed to help you detect IDs that are invalid
|
Mark M. |
however, you still are supposed to be updating your server's database to reflect what GCM IDs are (in theory) still outstanding
|
EGHDK |
Hmm... but again if my server has two gcm ids, mapped to one phone. How do I tell it to unregister the correct one?
|
Mark M. |
you can't unregister() the old one
|
EGHDK |
unregister() only unregisters the current gcm id?
|
Mark M. |
AFAIK
|
Jul 8 | 8:25 PM |
Mark M. |
the old one would have been erased when the old app installation was uninstalled
|
EGHDK |
Got it.
|
EGHDK |
I'll look into it more later.
|
EGHDK |
I'm trying to make a sample app that you can choose a movie from your gallery. Once you onActivityResult is valid, you'll be able to trim your video and resave it as a new clip. I don't know where to start with it. What would you recommend?
|
Mark M. |
where to start with what?
|
Mark M. |
choosing the movie?
|
Mark M. |
if so, the chapter on the MediaStore has a sample app demonstrating that
|
EGHDK |
I got the "choosing the movie" part. I'm not sure how to start implementing a trimming mechanism.
|
Mark M. |
are you expert in C/C++ and movie codecs?
|
EGHDK |
no...
|
Jul 8 | 8:30 PM |
Mark M. |
then I'd strongly recommend that you write another app
|
EGHDK |
Hah. It'd be that hard? No easy MediaPlayer trim methods or something...?
|
Mark M. |
no
|
EGHDK |
Alright. Well that solves that.
|
EGHDK |
You go over ndk in your book correct?
|
Mark M. |
and that's a wrap for today's chat
|
Mark M. |
yes, I have an NDK chapter
|
EGHDK |
Okay. Another rabbit hole for another day.
|
Mark M. |
not that big, as I haven't done much C/C++ in ~15 years
|
EGHDK |
Thanks mark.
|
Mark M. |
the transcript will be posted to http://commonsware.com/office-hours/ shortly
|
Mark M. |
the next chat is Thursday at 7:30pm US Eastern Time
|
Mark M. |
have a pleasant day!
|
EGHDK | has left the room |
Jeff G. | has left the room |
Mark M. | turned off guest access |