CS50 Tracks 2019 - Android - Lesson 4
Key Takeaways
Creates an Android app that applies filters to images using Java and Android libraries
Full Transcript
in this video we're going to be writing an Android app that applies filters to images much like Instagram we're going to write our own version using a few libraries that will download from the internet so let's get started just like before let's start a new Android studio project we're just going to select an empty activity because we're going to write this ourselves can name the application whatever you like I'm gonna go with 50 gram again our package name just edu Harvard cs50 that's fine wherever you'd like to save it make sure we've got Java at least 5.0 and then using Android X artifacts so we'll click finish okay and here is our empty project everything is automatic we've generated just as it was before let's just give this to run to make sure it looks like what we expect okay we've installed successfully and if we open up the emulator we've got that blank activity again so let's start by writing out the views for this application so we'll have a pretty simple UI let's just display a slot for the image that you're looking at then we'll just have a few different buttons one button is one to select an image and for that we're going to look into the images that the user has saved on their phone and then we'll just have a couple other buttons that let you apply different image effects to those images so to start writing our UI remember we're going to go into this resources folder into layout and open our layout XML file so just like we did last time let's get this textview out of the way we don't need that now by default this is using a constraint layout so let's look at a different container that we might use called a scroll view as it sounds a scroll view is going to allow you to scroll contents that might be too large for the screen in fact that recycler view that we looked at before is very similar because it's allowing you to scroll elements where the actual list is much larger than the size of the screen so let's change this constraint layout and let's instead make this a scrollview and notice that we're Auto completing automatically and everything else is going to stay the same let's just match parent as we did before now inside of the scroll view let's again use that linear layout since we're just going to be stacking things on top of each other we'll have the image view first and then a series of buttons below it let's add this linear layout we want the width to be match parent because that's going to fill the full width of the screen and we want the height to be wrap content we want the height of this linear layout to be equal to the sum of all the heights of everything inside of it so let's create that layout and now let's add a couple things to it to start the first thing we'll add is an image view as its name suggests you can use an image view to display an image so for this let's specify wrap content for both the width and the height and what this will do is make sure that the image view is just the size of the image that you load it that loads into it and let's also give this an ID because we know that we're going to want to access it later and let's just call it image view that's everything we need there so we can have a slash and end that tag and now blow it let's add a button in Android that's just button the width and height let's just wrap content again so the button is just big enough for the text then from there let's set the text of our button that's the same property we looked at before just Android text let's say this says choose photo okay so let's try running this and see what we get we installed successfully so let's pull up the emulator and right now there's no image loaded so that makes sense one last thing to do before we forget is to set that orientation so by default it's horizontal and so we just want to change that to vertical so that all of the elements stack on top of each other so now that our views are set up let's tackle this problem in two halves first let's figure out how we can let the user select a photo from their phone and display that photo in the image view then after that's working let's figure out how we can apply those filters to the image so everything is all set in the view so let's come back to our activity just like we did before let's get a reference to that image view so we can save that so let's say image view and inside of uncreate we're gonna say image view is fine view by ID and we gave that an ID of image view so next let's write a method to enable the user to select a file from their phone so let's just call this public void not returning anything and we'll call it choose photo so the way that you can pull up a file selector for the files on a user's phone is also with an intent but this time rather than specifying a class in our own application to open we're going to specify a system-wide intent so we can actually open some other app on the user's phone this is really nice because it means we don't have to manually write all of this ourselves it'd be a real pain if we had to write a whole image gallery from scratch right now instead we can just use the image gallery that's already built into Android so let's take a look we're gonna create an intent just like we did before but this time in the constructor we're going to specify intent dot action open document you can see here scrolling through the autocomplete all of the different things that you might want to specify but open document as the name suggests is going to open up this gallery view where you can select a file next we want to specify to this intent what type of file we're looking for so we're going to say intent dot set type this takes a string and we're looking for any type of image so the way to specify that is by saying image slash star so this says as long as the file type is an image it could be a JPEG or a ping or a jiff no matter what it is we want to open it so long as it's an image so lastly we just have to startup that activity so just like we did before we can say start activity for result we want to give it some intent and then we're also going to specify as the second argument what's called a request code and we'll just say one and this is basically a way to identify where the request came from so what's gonna happen remember is as soon as this line executes we're gonna get bounced out into some other activity and eventually that activity is going to finish we're going to come back to this activity and it could be the case that this activity starts off a few different intents maybe one to a file selector another to a camera maybe another to a web browser and when we come back to our application we want to know which intent we just came back from so in this case we'll only have one but this request code is basically a unique ID that tells us where we're coming back from so when we come back from this intent we're gonna say let's make sure the request code is one because that's the code we specified for this getting a file intent okay so the last thing to do here is to hook this method up to something you can see we're getting that same gray underlined we got before because it's not used so to do that let's jump back to our XML here and inside of our button let's say Android on click and then we just need to type the name of this method you don't need to specify the class or anything like that because Android already knows what activity is associated with this layout so you can see here that after I've specified this on click we're in this helpful error message it's saying the corresponding method handler choose photo view is not found that's because in order to do this we just have to specify a parameter here so we can just say view V let's make sure we automatically import it and so we're not actually going to use this parameter but if we wanted to this could tell us which button was pressed so in theory we could hook up the same event handler to a bunch of different buttons but we don't need to do that right now we can just specify we can just add this parameter and then not use it one last thing is that button looked a little small because I set the width to wrap content so let's actually set this width to match parent and now the button is going to be the full width of the screen so let's try running this app and see what happens we've installed successfully so let's open up the emulator and tap are now larger choose photo button nice so looks like we've opened up this new activity and it's blue it has all these nice controls and we didn't write this this is just something that's already built into Android and we've just popped out to there activity so if I select a photo nothing happens which makes sense we haven't specified what's going to happen when a user selects a photo but really with just those three lines of code we can open up this brand new activity with all this functionality already built-in for us so now let's take a look at how we'll handle that data that's coming from the activity to do that let's open up our main activity again and we're going to override a method called on activity result again we're just letting autocomplete do all of that for us but this is a method that's defined in that app compat activity that's going to be called by the system when I exit out of that activity I opened so once I select a photo I'm gonna jump into this method here now you'll notice the first parameter to this method is that request code so when I come back from that photo picker the value of this variable is going to be 1 next we have this result code and this basically is a way for the other activity to specify whether or not there was some kind of error lastly we're getting back an intent which as you'd guess is a way for that activity to pass back any data it wants back to me so the first thing you want to do is call super could be the case that this on activity results in app compat activity of doing something important so let's just call super to make sure now we want to check a couple things first we want to make sure that result code is okay so this is a special constant that's defined in the activity class it just indicates that nothing went wrong we just want to check for that and we also want to make sure that we've got some data back so we'll say and data is not equal to null if we didn't get any data back or something went wrong then we don't want to try to load the image so now we want to extract the image from this intent and doing so is a little bit of verbose there's a few different things we're going to have to do but let's just walk through them the first thing you're going to get from this intent is a URI object the URI is just like a URL it just sort of specifies the location of something and to get that I'm going to say data dot get data and so in this intent there's some data that's being passed along and this is going to give me a path to that data so now that I have a URI I want to open up that data since that URI is pointing to some image on disk to do that I'm going to call another method that's defined on activity called get content resolver this is just a special class that's going to allow you to do different file operations so there's a method on that class called open file descriptor and it looks like from my autocomplete this takes a couple arguments the first one is some URI to open and the second one is the mode to open it in so you might remember this from earlier in the course but if we specify our that's saying we just want to read this so my autocomplete tells me that this is going to return some object called a parcel file descriptor so let's just save that here so from that parcel file descriptor this is basically a wrapper around that content and looks like I've got a red underline here so let's see what it says it's unhandled exception so that means that somewhere in here these exception file not found could be thrown that makes sense because if I try to open up an invalid URI something could go wrong there so let's surround this block of code as we did last time in a try-catch so let's say try bump the indentation here and then we're going to catch this file not found exception if we do have that let's just use that log class again well log tag of cs50 will say image not found then again we'll pass along that exception object so that we can print it out finally we want to change this parcel file descriptor into a different type of object called a file descriptor luckily that's pretty easy we can just say file descriptor file descriptor is parcel file descriptor get file descriptor so this is kind of some of the verbosity I was talking about but all you're really doing is just going through a few different objects to eventually get the data that you want to get so now that I have a reference to this file descriptor I want to load it into an image object to do that I'm going to use the class bitmap this is a class that's also defined in Android and it's basically used to load images so for now let's just call this bitmap image so now to go from a file descriptor to an image I can say image you I'll use this class called bitmapfactory and this is just a class that has a bunch of static methods and when you see the word factory that basically means it's a class whose job it is to instantiate objects so inside a bitmap factory are some methods that are used to create bitmap objects one such method is one from a file descriptor so I have decode file descriptor here and that's where I can pass in my file descriptor so another convention would be to say new bitmap and pass something in another way to do that is just to have some factory and the factory is producing instances of bitmap so this D code file descriptor method it returns a bitmap object all right so just a couple more things to do let's close out this file descriptor since we don't need this file anymore we've already opened it we've decoded it we've loaded it into memory no reason to leave the file open anymore and now it looks like we've got another exception so this is Java IO exception so let's just change this file not found to an IO exception and it just so happens that that's going to cover all of the exceptions that might be thrown here and so now the last thing we need to do is just load up our image so from the image view we have this method set image bitmap that's going to take a bitmap object which is great because that's exactly what we have and now we can save this so just to recap what we just did there so we got back an intent from this other activity and this intent sent along some data in the form of a uri we then took that uri which is just a path to something on disk we opened it up we've loaded it into an image then we took that image and loaded it into the image view so the image view is ultimately what's going to display that data on the screen so let's try giving this a run everything looks like it installed successfully so let's jump to the emulator let's tap on choose photo select this photo that I already have downloaded onto my simulator and there we go we've displayed it and you'll notice that there's no sort of weird stretching or cropping happening with the photo and that's because we've specified that wrap content rather than giving it an explicit height or width so now that we have this photo loaded let's apply some image filters to it so Android doesn't have a lot of this built in so we're going to turn to some third-party libraries to use some image filters so let's take a look at the libraries that we'll use this first library is an image library and I'm on the github page here and it says Android transformation library providing a variety of image transforms great so let's scroll down a bit and they have this handy dandy jiff that shows you all of the different transforms that they can apply to an image so I've got some cool stuff here looks like they've got a sepia thing the sketch one looks pretty cool so that this library looks pretty good I want to use this one so then we have this section how do I use it and this is a snippet from a Gradle file so it looks here like we have another implementation line we've seen this before but at the end of it it says for xxxx we're actually meant to replace that with the actual version of the library what we want to use so let's do two things first let's just copy this and we'll add this to our Gradle file just like we did before paste it in but we don't want to leave those two x's so let's go back to this github page and at the top you can see the latest version is for point 1.0 so we're just going to type that in for point 1.0 so let's come back to github and it also says if you want to use the GPU filters no I don't know what that is so let's just kind of keep scrolling transformations then okay so here's this GPU filter thing and okay there's that sepia there's that sketch so it turns out I do want to use this other thing so they link to this other repo here and that's this library that this other I breed depends on so in order to use those transforms we just have to load in this other library same thing this gives its own little implementation line let's just copy that paste that into our Gradle file and then just like before let's just replace those X's with the current version looks like it's 2 0.4 so 2 0 4 and now we've added those dependencies to our project let's click sync to actually download them looks good the sync was successful so now we can start using these libraries so the first thing we want to do is add a few more buttons to our view so let's go ahead and do that let's just start with one let's copy this button and we'll change the text to let's let's start with that sepia filter I really like that one and then on click let's call a method called applied sepia we're going to get a red underline immediately because we haven't defined that method yet so let's go ahead and do that public void apply sepia again let's just give it that view parameter we're probably not going to use it but it needs to be there and let's just give our project to make to make sure there's no errors and there's not so it looks like we've compiled successfully okay so now we're ready to start writing our filters so I just found this library so I'm not really sure how to use it yet so let's check out its documentation so here we are on the github page again we can scroll past the demo and here's a couple examples of what to do so it looks like this is using this other library called Glide and I haven't loaded that in yet so let's just make sure I if I need it or not so if I click on this link here yep so this looks like it's just another library just a sort of generic image library that this other library also depends on so simple let's just copy paste this into our Gradle file sync and we're good to go so now I have that last dependency that I need so now I can start following this example so it looks like I can say glide here's some static class that's provided in that glide library it's gonna say with this so this is probably a reference to some activity then it looks like there's a load method where I can load in some image and then I have this method called apply so okay that looks neat looks like you can apply some transformations here that's great that's what I want to do and then finally there's this method into that looks like it takes an image view and so what that's going to do is draw out the result of those transformations into an image view and so that's good this looks like it's really easy it's just one line of code to apply to load an image apply filters to it and load it into my image view so that's great that's that's exactly what I want to do so let's let's give this a shot with that sepia filter okay so let's open up this main activity and follow those instructions let's say Glide dot with this that's my activity then what was next next was load looks like there's a load method here that takes a bitmap I called my bitmap image all right after I loaded it I wanted to apply some filter now let's just jump back to documentation to see what the argument is so okay looks like we want to say request options request options then there's that bitmap transform I've got a bitmap so that looks right and then I want to specify a transformation so let's go back and see if I can remember okay so it's this sepia filter transformation let's create a new one of those and let's see so okay I haven't import of this yet so I can just have Android studio automatically import that for me now let's just format this a little nicely so I'll have one per line so that's going to apply the transformation and last they're going to specify an image view to load it into there we go that's that same one line that we just looked at but this time we're applying the filter that we want and you notice here Android studio is being a little helpful again it's telling you at each stage of this chain what each step is returning so this first step looks like it returns a request manager and so on so now let's try giving this a shot let's run our app okay looks like we're installed there's our new sepia button let's click Choose photo select that photo and then add sepia and there we go we've applied an effect to that image so now let's add a few other filters to see what else this library can do a couple that caught my eye on this list was one was tune and one was sketch so let's just add both of those just like I did before let's add a couple buttons first let's go one here and one here so let's say this one is tuned we'll call this apply tune and this one is sketch we'll call this apply sketch okay my layout is good to go let's jump back to the activity let's define those two methods public void apply tune and public void apply sketch okay looks good and so now naively what I could do is just kind of copy paste this code and say I was going to copy it here let's just switch this to two and filter transformation but there's kind of a lot of repeated code there and so let's see if we can factor some of this out into a separate method so let's look at these two method implementations and it's mostly the same so let's see what's different it looks like the only difference is this transformation object so maybe let's create a new method let's just called apply and let's pass in that transformation object the problem is is that we need to specify a type and it doesn't look like from just reading this code that they're the same type they're these two different classes but maybe there's some common base class or interface that they both share and then we can use that as our type instead so as a shortcut to figure out what that might be I'm gonna use my autocomplete so I'm going to go back to request options and just take a look at this method again and you'll notice that as soon as I do that it's going to tell me the type that's passed into this method and it looks like that type is a transformation of type bitmap so that's the type that I can use in my new method both of those transformations implement this interface or extend this class doesn't matter all that matters is that it's a type that I can use so that means that we want our type to be a transformation of a bitmap and we'll just call it filter awesome so now let's move this code into apply now rather than using this sepia filter transformation we're going to use the filter that we passed in okay so now let's use this method let's say apply and then we're going to pass in a new sepia filter transformation and similarly here we can remove this and apply a tuned filter transformation so now let's run a make on this project so it looks like we have some compile errors here let's take a look at what it is so this says type Android view animation does not take parameters and so that looks a little suspicious because that's not actually the transformation that we wanted to import so Android studio actually auto imported the wrong thing so let's just jump back up to our imports expand this and let's look for that transformation and we can just get rid of that you notice we also have another unused import so let's get rid of that what we actually want to import is that other transformation so we're looking to import when we look at this using autocomplete again this was the name of that library so let's use that instead so now we can just get rid of this again now if we scroll back up to that import list you can see now we're importing the right transformation and so this is where packages are really important because you might have some class game like transformation that's used in a few different packages we found out that apparently there's some Android class called transformation but it's in a different package so we want to make sure that we're always importing from the right package in order to use the right class so let's try building again there we go no compile errors this time so let's try it out all right we've installed successfully let's pick our photo make sure sepia still works it does now here's where this scroll view is going to be handy you'll notice that not all the buttons fit on the screen so we already added that scroll views we can scroll around now let's try out our new filter all right that's pretty interesting and so now let's add that one last filter but we can do so really really quickly because we've already have this helper method so all we need to do is say apply and then let's just pass in that sketch filter I don't remember what it's called but the autocomplete saved me so now let's run the app one last time and check out our new filter installed successfully let's pick our photo hit the new sketch button and there's our filter so that's it we've built our simple image filter app and notice how simple that was we're really able to leverage those third-party libraries and use code that other people wrote bring that into our app and then build something really cool with only a few lines of code
Original Description
***
This is CS50, Harvard University's introduction to the intellectual enterprises of computer science and the art of programming.
***
HOW TO SUBSCRIBE
http://www.youtube.com/subscription_center?add_user=cs50tv
HOW TO TAKE CS50
edX: https://cs50.edx.org/
Harvard Extension School: https://cs50.harvard.edu/extension
Harvard Summer School: https://cs50.harvard.edu/summer
OpenCourseWare: https://cs50.harvard.edu/x
HOW TO JOIN CS50 COMMUNITIES
Discord: https://discord.gg/T8QZqRx
Ed: https://cs50.harvard.edu/x/ed
Facebook Group: https://www.facebook.com/groups/cs50/
Faceboook Page: https://www.facebook.com/cs50/
GitHub: https://github.com/cs50
Gitter: https://gitter.im/cs50/x
Instagram: https://instagram.com/cs50
LinkedIn Group: https://www.linkedin.com/groups/7437240/
LinkedIn Page: https://www.linkedin.com/school/cs50/
Quora: https://www.quora.com/topic/CS50
Slack: https://cs50.edx.org/slack
Snapchat: https://www.snapchat.com/add/cs50
Twitter: https://twitter.com/cs50
YouTube: http://www.youtube.com/cs50
HOW TO FOLLOW DAVID J. MALAN
Facebook: https://www.facebook.com/dmalan
GitHub: https://github.com/dmalan
Instagram: https://www.instagram.com/davidjmalan/
LinkedIn: https://www.linkedin.com/in/malan/
Quora: https://www.quora.com/profile/David-J-Malan
Twitter: https://twitter.com/davidjmalan
***
CS50 SHOP
https://cs50.harvardshop.com/
***
LICENSE
CC BY-NC-SA 4.0
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License
https://creativecommons.org/licenses/by-nc-sa/4.0/
David J. Malan
https://cs.harvard.edu/malan
malan@harvard.edu
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from CS50 · CS50 · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Hello, World: Hadi Partovi
CS50
Content Distribution and Archival in a Digital Age
CS50
CS50 2014 - Week 1
CS50
CS50 2014 - Week 3
CS50
CS50 2014 - Week 0, continued
CS50
CS50 2014 - Week 4
CS50
Week 3, continued
CS50
Quiz 0 Review
CS50
CS50 2014 - Week 3, continued
CS50
CS50 2014 - Week 7
CS50
CS50 2014 - Week 7, continued
CS50
Breaking Through The (Google) Glass Ceiling by Christopher Bartholomew
CS50
Introduction to Amazon Web Services by Leo Zhadanovsky
CS50
CS50 2014 - Week 9
CS50
How to Build Innovative Technologies by Abby Fichtner
CS50
Light Your World (with Hue Bulbs) by Dan Bradley
CS50
Building Dynamic Web Apps with Laravel by Eric Ouyang
CS50
CS50 2014 - CS50 Lecture by Steve Ballmer
CS50
CS50 2014 - Week 10
CS50
This is CS50 with Steve Ballmer?
CS50
Meteor: a better way to build apps by Roger Zurawicki
CS50
Data Analysis in R by Dustin Tran
CS50
Data Visualization and D3 by David Chouinard
CS50
CS50 2014 - Week 6
CS50
Build Tomorrow's Library by Jeffrey Licht
CS50
CS50 2014 - Week 9, continued
CS50
Essential Scale-Out Computing by James Cuff
CS50
iOS App Development with Swift by Dan Armendariz
CS50
Sam Clark Leads Yale Students on Tour to CS50 at Harvard
CS50
3D Modeling and Manufacture by Ansel Duff
CS50
CS50 2014 - Week 5, continued
CS50
hello, world
CS50
CS50 2014 - Deep Thoughts - Hash Table
CS50
CS50 2014 - Deep Thoughts - Binary Tree
CS50
CS50 2014 - Deep Thoughts - Scratch
CS50
CS50 2014 - Deep Thoughts - MySQL
CS50
LaunchCode Visits CS50
CS50
CS50 Live, Episode 100
CS50
CS50 Field Trip to Google
CS50
This is CS50 AP
CS50
Week 4: Monday - CS50 2011 - Harvard University
CS50
Week 2: Wednesday - CS50 2011 - Harvard University
CS50
Week 1: Wednesday - CS50 2011 - Harvard University
CS50
Week 11: Monday - CS50 2011 - Harvard University
CS50
Week 3: Wednesday - CS50 2011 - Harvard University
CS50
Week 12: Monday - CS50 2011 - Harvard University
CS50
Week 1: Friday - CS50 2011 - Harvard University
CS50
Week 3: Monday - CS50 2011 - Harvard University
CS50
Week 10: Wednesday - CS50 2011 - Harvard University
CS50
Week 2: Monday - CS50 2011 - Harvard University
CS50
Week 9: Monday - CS50 2011 - Harvard University
CS50
Week 7: Monday - CS50 2011 - Harvard University
CS50
Week 5: Monday - CS50 2011 - Harvard University
CS50
Week 5: Wednesday - CS50 2011 - Harvard University
CS50
Week 7: Wednesday - CS50 2011 - Harvard University
CS50
Week 8: Monday - CS50 2011 - Harvard University
CS50
Week 9: Wednesday - CS50 2011 - Harvard University
CS50
Week 8: Wednesday - CS50 2011 - Harvard University
CS50
Week 10: Monday - CS50 2011 - Harvard University
CS50
Week 2: Wednesday - CS50 2010 - Harvard University
CS50
Related Reads
📰
📰
📰
📰
Indian AI coding startup Emergent becomes a unicorn with $130M Series C
TechCrunch AI
Disposable software
Seth Godin's Blog
Join live event: Building With AI Without Creating Technical Debt
Reddit r/learnprogramming
I Built an AI Coding Cost Tracker to Finally See What Copilot and Cursor Are Actually Costing Me
Dev.to AI
🎓
Tutor Explanation
DeepCamp AI