All right, so let's get started creating a bitmap async task inside of our main activity, and I do
that just on top of this companion object.
So here private in our class bitmap async task.
OK, and the parameters that I want to define here is going to be M bitmap, which will be of type bitmap.
So basically, I want to get a bitmap whenever we create a bitmap async task and whatever, we execute
it.
And it should, of course, inherit from async task.
So here, any void and string needs to be passed through this async task, and I'm going to put that
in the next line so it's a little more readable here and then here, of course, that's going to be
the code that we want to execute in this bitmap async task.
And as you can see, it's complaining because it says I need to implement something.
So I need to implement members.
And the only member that I need to implement is going to be an hour or two in background.
All right.
So let's do that.
As you can see, it doesn't expect us to also have this pre execute or on pre execute.
Neither does it ask us to add on post execute.
But I want to have it.
I want to have the home post execute in here because I then want to inform the user where they toast,
that everything has been done so that we're done with it.
So let's implement something in this do in background.
First of all, I'm going to create the result variable, which will be a string because as you can see,
we need to return something in our doing background.
So it would be good to return something later on.
And then I'm going to check if the bitmap that is passed to my bitmap async task here at the top.
If that bitmap is not not because only if it's not null, then I want to do something.
And what do I want to do?
Well, I want to do something that could go wrong because I'm going to work with output streams.
And I told you once earlier, once you work with streams, you should use try and catch, because if
you don't use, try and catch, then streams can go wrong.
And I think they even require you to do that.
So let's just try real quick while Val Bytes is equal byte array.
How to put stream.
When you use that, OK, well, it's not complaining yet, but at one point it might.
So let's just be safe and to try and catch around that, because in the trial, that's where we're going
to do all the magic that could go wrong.
And in the catch, we're just going to catch the exceptions that could appear.
And I'm just going to say that I don't want to have any specific exceptions, but just a general one.
The exception.
And in this case, I'm just going to say that the result will be empty and I'm going to set the stage
actress.
So this result is going to be empty in this case.
And now let's actually return it let's return it in here, because it's still complaining here at the
bottom.
We're still getting an error as we return this result.
And of course, I want to return a significant result, something that is useful because right now it's
not really useful.
The result is just going to be an empty string either way.
So here we say it's an empty string.
And even in the case, if something goes wrong, we also say there's going to be an empty string.
But I want to actually do something cool with it.
So in order to do so, I'm going to create and byte array output string and then I'm going to compress
my bitmap.
So I'm going to compress it.
And here we need to pass the compress format.
So bitmap that compress format.
And I'm just going to say that I want to have a P and G file, so please make it out of my image.
Panji, you can see if jpeg pg weap.
So I'm just going to use PG, I can assign the quality, I'm just going to say 90 percent quality is
good enough and then the wide our array output stream and I'm going to use bitts maybe we could have
a more.
Significant name, but it's going to be fine, so what it is, is a wide array output stream and you
need to pass that when you want to compress something.
So if we look at this compressed method, you can see it needs a compressed format, it needs a quality
and it needs an output stream.
And the output stream that we are going to use is in byte array output stream.
So it's going to put all of those bytes out there in the right format in order to create a Penghu file.
Which then will be stored on our device.
This by itself is already pretty cool, but the problem is it's still not in the right format because
the format that we need is the actual file.
So we are already compressing it with compressing the bitmap to a PNG.
But we need to make it a file.
So let's create a file out of it if it's going to be of type file.
And here we need to give it a half name.
And by the way, let's import that.
So it's going to be a little easier to.
Finalize the code in here, and his file now needs a name.
So let's give it the name and this one is going to be a pretty long one, but let's just do it.
So external cash directory, the absolute file.
Talk to String, so this is the cash directory of our device, then the absolute file name to string
and then we have a file separator file that separator.
Plus.
And I'm going to call this one kid's drawing.
Help underscore and then system that current milliseconds divided by one thousand plus dot Panji.
OK, pretty long name.
Let's break it down.
So what is happening here?
Well, we get the external directory then to sort of file returns to absolute form of this abstract
path.
Name the file separator.
Is the system dependent default name separate a character string contains just a single character,
this false operator, then we give it the name kids drawing up on the score.
Whatever time has passed since the 1st of January, nineteen seventies, divided by one thousand.
And then I call this PG.
So what we do with this is we make sure that each file gets a unique name.
Because this number will constantly change, so even just one millisecond later, it will be a different
file name.
So even if we create one file every millisecond, each of them will have a separate name.
Of course, this process isn't going to be as fast, so it's not going to be done within one millisecond.
OK, so that's that then.
The next thing is we need to put or create a file output stream.
So now we prepare to file, so to speak, but now we need to actually put it out.
So let's do that in here.
Value EFO stands for File Output Stream and you could of course, call this Everquest.
Maybe that's a little more telling and you need to pass the file in here.
So the file output stream will need to have this file, which is our file that we created here, and
then we can start writing onto this F OS.
So that's right.
And what do we write?
Bytes to Vitara.
And then we need to close this whole thing.
So let's close it this file output stream, because once you open a stream, it will stay open until
you close it.
That's why it's important to actually close it.
And then.
Let's store the result.
As being half that absolute path.
So what happens here is pretty complicated, so there's a lot of stuff going on right, and we're using
a lot of classes that we have never used before.
But this is just generally the structure that you need when you want to store something on your device.
And first of all, you need to have an output stream, which is of type, by the way.
So byte array output stream, which is of a type of output stream.
You can see we have another output stream, which is this file output stream, but we just need both
of them because as you can see here, when actually writing, they come together because Bite's is our
array output stream and we need to write in an byte array to then again write in our file output stream.
And then once that is done, we will actually have the file at a position which is our absolute path,
which is the directory which we have defined within file.
So the position on our phone where we want to store this whole thing.
OK, that's it.
So now what's left to do is to.
Let the user know that it worked or didn't work, so let's write something in this post, execute on
post, execute here and I'm just going to paste it, then you can leave it out.
It's not really mandatory, but it's still good for the user to know.
So unposed execute.
And as you can see during the recordings of this and so the time between the preparation and the recording,
what they changed is that the result of the unposed executed now is an nullable.
So what I will need to do is I'll need to check here.
If the result is in fact empty and I'm just going to force unwrap it here and then toast, make Text's
a fail safe successfully.
So if it worked, cool, if it doesn't work, something went wrong while saving the file.
And now there's one final step left to do because we have prepared this whole bitmap async task, but
you can see it's still great because it's never used.
Now, in order to use it, let's go back to our.
Uncreate method, because in here we have this button, which is actually not even there yet, we didn't
need to add it.
So let's add this button, I.B. on this score, save thought said Unclick Listener.
So what we do here is once somebody clicks on this save button here, this image button.
What we want to do is we want to access something, so if.
Is read, storage is allowed, and only if that's allowed, then.
Run our bitmap async task.
And what do we need to pass here?
Well, we need to pass in the bitmap, where do we get this map from?
Well, we get it from our.
Bitmap Holder or our view, so to speak, so all the way up here, we have this strong view.
Which actually.
Is inside our frame layout, so what we want to have is the actual frame layout, the whole frame layout
view, because it contains the image view you, which is the background and it contains the drawing
view, which is what we have drawn.
So we want to have both.
That's why we need to use this frame layout as the view that we want to make a bitmap from so bitmap
async task.
We passed a bitmap from F.L. Drawing, but we want to get it as a bitmap type because now it's of Taibu.
But we can call this method called get bitmap from view and we can pass a view in there, which is our
container.
And then finally, we, of course, need to execute that thing.
So execute and that will then go ahead and run with an amazing task, pass in our container to make
it a bitmap.
So passing the bitmap of our container, which is a view.
Right.
And then it goes through this whole doing background process that we have prepared here.
So it's going to be our bitmap.
So once again, this frame layout, which contains our image for you and our drawing view, is going
to be passed in there as the bitmap, then in the background, it's going to do all of that stuff where
it's going to try to create an image which is going to be a physical dimension of by physical, I mean,
of course, it's going to be a file on the drive of the device and then.
Done pretty much.
OK, but if we don't have access, by the way, here to top in our IBSA set unclick, listen up, if
we don't have access, we want to request permission to get permission to have access to this storage.
So request storage permission.
Now, let's look at stories, permission, what we did there.
We not only asked for external, but we also asked for external storage permission because we wanted
to have both.
Right.
And at this point, we can finally test our application and see if all of that has worked.
So there we are.
Let's take our Homer Simpson with a doughnut as the background image.
Then let's draw eyes as on top of his belly.
So now he's Superman, maybe even the Superman logo.
I'm very bad at logo.
So this is supposed to be the Superman logo, and now let's save it.
And Piquancy file was successfully stored in your case, might be the case that it still will request
for permission, but I think we already got that or we already gave that.
So now if we store that, the file will be stored at Android data.
You let's look at it again.
You could be drawing up cash.
So it's within that folder.
So how do we get there?
Well, on the emulator, we need to go to files.
Then here onto Android SDK, Android data.
And then EU tutorials kids catch and then you can see with all three images, because I save three times.
Already.
So that's it for this video.
I'd say this is by far the most challenging part of this whole application, but you have learned so
many new things and really advanced stuff already, even though this is just the third application that
we're building our fourth or something.
So you can see we're doing so many different things already.
We're asking for permission.
We're storing something on the device.
We're using background async tasks which run in the background.
And now there are only two things left to do in this app.
And one of them is to run this background and see that it's running in the background because now it's
actually doing that super quickly.
Right.
It just happens within a very short period of time.
But still, if something in the background is happening and the user expects for some feedback or expect
feedback, then it makes sense to at least show a little indicator.
That's what we're going to implement in the next video.
And afterwards, we're going to implement how to share the image with our friends.
So then we will be able to share something.
And I will show you how to add the share feature to your app.
So see you in the next video.