Alright so moving on now, now that we've got the data we want, we're going to create a new photo object passing
the values we've just extracted from the json data in the constructor.
So the photo object can then be added to the list that we want, that we'll be returning, so I'd better declare
an array list at the start of the function as well. This is the doInBackground,
so let's do that, and I'll declare that under the log so we'll do a val photo list is equal to array list,
diamond operator and it's going to be photo, so it's an array list of photo objects.
And let's go ahead now and create an object, a photo object from the json data, so down here under
the val link, we're going to put val photo object is equal to photo, parentheses title author author Id
link tags and photoUrl. And because we've now got an array list we can do a photo list dot add
photo object. Let's also do a log here, so Log.d
parentheses tag comma dot doInBackground dollar photo object. So that's basically added logging there,
at the end of the function to print out the data, just so we can check that everything's working as it should be.
So the code will keep looping until it's processed
all the items in the array, and we'll then end up with a list containing the details for each of the photos
in the feed. So that's json passing.
Now we haven't had to write a lot of code, and all the complexity of parsing json data is dealt with
by the json objects in the org dot json package, which is pretty cool.
So let's clear this error down here now, which relates to adding a catch block. So we're going to add a catch parentheses
e colon JSONException, then a code block, and we'll start by doing a e.printStackTrace, then we'll do a Log dot
e parentheses tag comma dot doInBackground, colon Error processing
Json data dot, then we'll do a dollar, left and right curly braces e.dot message, which'll return the message passed by the
json exception. And then we'll do, basically I'm going to cancel this one, so just a note here to cancel,
true, because that's essentially what's going to happen, we're cancelling out of it.
So do a listener dot onError parentheses e, parsing the actual error.
So the catch block prints a stack trace with the code on line 47, then prints the message contained in an
exception by calling its get message function.
Now because our code's thrown an exception, we call the onError function of our listener
to parse the exception back to the calling code.
Now as I said earlier, this code's running on a separate thread.
So that means that the calling code can't trap the exception using a try catch block,
so we'll use this mechanism to let the caller know about any errors that may happen.
Now I'm going to come back to this cancel true line that I've included as a comment a bit later.
It'll makes sense when we've got the code running so I'll describe it then.
Now the only other thing left to do is to return a list of photos that we've created.
So let's go ahead and do that, and I'll get rid of that last error. First we'll do a log. so Log.d parentheses
TAG comma,
double quotes dot doInBackground ends, and then we'll do a return photo list. So that now clears the
final error, because our function's now returning something.
OK so when doInBackground finishes, the onPostExecute function will be called.
So I'm going to use that to send the list of photos back to the calling code.
So let's have a look at that, so onPostExecute.
At the moment we've got the log and the super, so leave that in. On the next line we'll put Listener.onData
Available, and in parentheses, result. Now we've got an error there, or I have anyway, you may not have.
This function is declared to have a nullable parameter, and we've specified a not-nullable argument to
onDataAvailable. Now we've already made sure that doInBackground can't return null,
so it's OK to change the onPostExecute parameter to be non-nullable.
So let's go ahead and do that. And then lastly we'll add some logging, so
Log.d parentheses tag comma dot onPostExecute ends.
Alright so that's how json parser finished. Now if everything worked,
the calling class will have the photo list in it's onDataAvailable function, and can display
the photos or do whatever else it wants with them.
We can now get main activity to use this class to parse the data
after get raw data's finished downloading it.
So go back to main activity, so the place to perform the parsing's in the onDownloadComplete
function, down here, and specifically if the status we got back is OK.
So at the moment we're just adding some logging there. So now we're going to do
val getFlickrJSONData is equal to GetFlickrJsonData parenthesis this, that's the listener
again, then on the next line getFlickerJsonData.execute, and we're passing data.
Now we've got this error because main activity isn't implementing the on data available interface yet.
So let's do that, back up here to the class definition. So we've got AppCompactActivity comma get raw data dot on
download complete. We also want to add, so comma onDataAvailable.
OK so we've now got another error but we expected that. We're not yet implementing the required functions for
this interface.
So let's go down to the bottom and we'll get Android Studio to generate the stubs for us.
Now the ones we want are relating to the onDataAvailable here, onDataAvailable and onError.
So I'm going to select both of those, click OK, and by doing that we've removed that error.
Now onDataAvailable will receive a list of photo objects, and we'll be using that list to display the
details on the screen.
For now though, we're just going to print the list so that we can see that everything's working.
We'll also had the usual logging, so let's go ahead and do that. So for onDataAvailable,
we're going to start with our log, the Log.d parenthesis TAG comma double quotes, dot onData
Available called, data is dollar data. Then we'll just do a space there for future function.
I'll do Log.d parentheses TAG comma double quotes dot onDataAvailable ends, and for onError,
we're just going to do Log.d parentheses TAG comma on
Error called with dollar, left and right curly braces, e dot, sorry, exception because exception's the name of the
parameter exception dot message. Alright so let's look at this slide again.
So you can see that MainActivity now implements two interface: the onDownloadComplete interface
that's defined in GetRawData, and the onDataAvailable interface from our new GetFlickrJsonData class.
Now the download started by creating a GetRawObject, or GetRawData object in onCreate. When the
download completes, the onDownloadComplete function gets called. That kicks off parsing the data by creating
a GetFlickrJsonData instance,
and when the parsing completes, the onDataAvailable function gets called. Now we'll add the code to display
the data later,
so we still haven't implemented the left hand side of this diagram, but we have finished the classes on the
right hand side now though.
So at this point when we're ready to run the program and see if our parsing works. Alright,
so let's now run this again and see if it works.
So we're going to come up and start it, and actually what we should do is open log cat. And while I remember we've still
got a filter on over here, so we can either take the filter off, or what we can do now that we've written
the GetFlickrdjacentData class, we can add that to the filter so I think I might do that.
So I'm going to add a pipe at the end of that, and do a getflickrjsondata, so we can also get output from
that as well. And we can see that when I've done that,
we've actually got an error here, system dot error. So something's actually crashed, and the error we've got back is
'onError called with no value for m'. So that, I suspect, we know for sure now,
it's relating to GetFlickrJsonData, the class doInBackground.
So let's just go and have a look at that,
and it's most likely something to do with retrieving the fields I would think.
And this is a hint here, the fact that json media is never used. That tells me that I've made a typo, so
I'm going to copy that, and that should have actually been here for the photo url.
So we should have been using that, so we're retrieving the json object into json media.
The photo is actually being extracted from json media.
That's the correct way to do it so that should actually, hopefully, fix that problem.
So let's run this again, I'll clear log cat.
OK so we've got some different data this time, much better looking,
and I think we might have fixed that problem.
So if we scroll up and have a look first, we can see clearly here now that GetFlickrJsonData class is
logging the data. So it's logging each photo as it's being parsed, and that's in it's doInBackground method as
you can see there. It's printing it out, but if we go up further,
we can see where the doInBackground was actually started.
But in terms of the raw data itself, if you scroll up and have a look. If you recall we've got the raw
json file that we downloaded, being logged in onDownloadComplete,
but also if we scroll up and have a look, onPostExecute and GetRawData as well.
So now that we can see that things are working, we're going to start commenting out that logging, but if we scroll it
back down again, and have a look at our GetFlickrJsonData, the call, you can see doInBackground starts
here. So that's from again,
the GetFlickrJsonData class, and it's parsing each set of details for the photos. You can see that as
it's doing that, we're getting each one logged, the information relating to the various fields, title, link and so
on. So that's working nicely, so
basically title, author, author Id, and link, and actually we can go right across, we can see tags as well.
You can see the image there, we can see tags, all working nicely.
So the parsing seems to be working, and when it completes, if we go right down to the end of the log, we've got the onDataAvailable
function being called which is correct,
and then onPostExecute actually ends right on the last line. Right, so at this point now that we've got the
json data parsing correctly, we don't need to log the raw json data any more, so
let's tidy up that log cat a little bit.
So going back to, well we're in actually, MainActivity, so we'll stay in there,
and what we'll do is we'll remove the data being logged in the onDownloadComplete function.
So what I'm going to do is just remove this part here,
so we've still got a message to say it's being called, but we just don't get the actual data.
And I'll fix that, that's a typo, onDownloadComplete it should have been, not on completed, the name of the function.
Right, so that's main activity, and the other thing is it's been logged in onPostExecute and get raw data. So lets
also remove that from this line, this logging line, so that we don't see all that raw json data anymore,
because we've confirmed that the json parser is working, and it's just basically making the log far too
big for us to actually try and figure out, to make any sense of, so we're removing it from the log.
Alright, we're going to run it again, and hopefully now the output will be a lot tidier.
Alright, so you can see now that I've removed that raw data, things are a heck of a lot tidier than what they
were before now.
And we're still getting the function calls logged, so you can see the order that everything's happening.
So the onCreate function in MainActivity creates a get raw data object to perform the downloading.
Once the download's complete, the onPostExecute function, well that calls onDownloadComplete, and on
DownloadComplete,
actually here, you can see it here being called, that actually creates a GetFlickrJsonData object
to parse the json into our list of photos, and we can see if I scroll down a little bit further, doInBackground starts.
Then we can see each photo being created as it's going through the json data,
and parsing it. And keep in mind here that when that's finished, the GetFlickrJsonData's onPostExecute should be called,
and you can see that down there, it starts onPostExecute.
And by the way the Android framework takes care of that.
That's what the execute method of an async task does.
So it runs the doInBackground function on a separate thread,
then calls onPostExecute with the result.
So onPostExecute then calls the onDataAvailable function in MainActivity that sends it
the list of photos.
So you can see all the photos in the list there,
and that's because that's the array list we're printing out now. Instead of an individual list of photos that you just saw
higher in the log,
this is the complete list of photos in an array list being printed out. Alright so the last
thing we want to do is to check what happens if there's an error, while parsing the data.
Now I did have a typo anyway which actually caused that to actually error, before we actually fixed
it earlier in this video,
but let's just go through and show you how to simulate that and just check that
what happens if we've got some invalid json data or if the json parser fails some reason. So we can
go back to MainActivity to do that.
That's the quickest way, and to duplicate the call, the execute, the GetFlickrJsonData.execute, duplicate that with
command d, control d on a PC, and if you just send some, basically some bogus data in there, I'm just
going to say bogus data. If we run that, and you can see we've got an error.
Very similar error, or the actual log's very similar to what happened before I actually fixed the typo
I made in GetFlickrJsonData. But you can see here it's actually saying what the
actual error is, 'Error processing Json data. Value bogus of type java dot
lang dot String cannot be converted to a JSON Object'.
And again that's correct because it's not valid json data.
So I'm getting the error log there.
And also if you look further down, you can see that onError is also called, with the same message there.
So we're basically seeing the log twice because the error is actually passed rather back to main activity in it's
onError function.
So that's why I may have passing rather an exception to the caller from code that's running on a separate thread.
But there's a slight problem with this as we can see in the log cat.
So even though we got an error while parsing the data, the onPostExecute method still gets called,
so that in turn passes an empty list to onDataAvailable, and you can see this down here in this part
of the log.
Now we really don't want that to happen if there's an error.
Now fortunately though the async task class has a way to prevent that.
So async task will only call onPostExecute when doInBackground finishes.
It won't do it, won't do that call if the task's cancelled.
Now async task has a cancel method which lets the main thread cancel a long running task if necessary.
Now we will be doing that later, when we look at how to handle the activity being destroyed by an
orientation change. But there's no reason why an async task can't cancel itself though,
and that seems like a good idea to do, if we get an error.
So going back to GetFlickerJsonData, that's why we've got this cancel commented out code here, in the
catch for the json exception errors. So I'm going to uncomment that line now, and just format it correctly.
So if we cancel the task when there's an exception, the async task code won't call onPostExecute, which
is what we want here.
So let's just run the app again and confirm that that is the case, and that happens if there is an error.
Open the log cat,
and you can see that we've got a different result this time. Actually I might just clear the log and run it
again, so we can see the fresh output,
and that looks better as you can see. We get the exception message logged by
the GetFlickrJsonData dot onPostExecute,
and again by MainActivity onDownloadComplete, and then MainActivity onError,
but then the doInBackground actually ends down here as you can see, after showing the actual errors.
So basically onPostExecute doesn't get called in that scenario, and MainActivity doesn't have to then
deal with an empty list. Alright so that's our two async tasks
now working. What I'll do before we end the video is I'll go back to MainActivity.
I'm going to fix this line here. I'm
actually just going to delete that line entirely, and uncomment the previous line so we've got some valid
data when we actually start the next video.
So I'll stop the video now and in the next one we're going to sort out the url so that we can add the
tag parameters to it, and that's going to allow us to return data for different searches.
So I'll see you in the next video.