Welcome back.
And the last video we prepared this method get bitmap from view, where we just paste a view in and
it will return a bitmap.
And now we're going to look at how we can store such a bitmap onto our device.
And I'm going to create a co-writing, therefore.
So we need to use to suspend keyboard, suspend Fong.
And I'm going to call this method bitmap file.
So we'll safe bitmap file to be precise.
And we need to have a bitmap.
So let's add a bitmap multiple here, which will return a string.
OK, so this will be the structure of our suspend function.
So first of all, I need to create a variable that will contain the result.
So so what?
We're storing the image and then we need to use with context.
And in order to use with context, we need to import with context.
So in order to do that, let's go over to our Gradle file and add the.
Dependencies.
So here we need to make sure that we add the dependency.
So we're in the Gradle file for app, and the dependency that we're going to require is going to be
the activity.
Katy X.
So here implementation.
Android X activity, Kolan activity minus Katy X, and we can use the beta, in my case, beta 01,
so that version here and then we need to sync it, otherwise we cannot use all of this code routine
stuff.
OK?
Once the Gradle is done and the thinking is done, we can go back to the main activity.
OK.
In my case, it's done now.
Now we can use with context or we can import with context.
So let me just go ahead and rewrite it with context.
You can see now I can actually use it.
OK.
And then I need to add the thread that I want to run this on, and I'm going to use the dispatcher's
I, as we have seen in the demo.
OK.
This bettcher's that i o the input output this picture and we are outputting something right?
We're outputting an image.
That's the idea behind this.
Function, so first, we check if the bitmap that is given to us so in bitmap is not equal null because
only if that's the case, then I want this to run because we can call this method with an empty bitmap
and it will just do nothing or it will still work in a way.
OK.
And then because things can go wrong doing what we're going to do, so storing something using output
streams and stuff, we need to use a try block here.
So I will create this variable byte, which will be a byte array output stream.
So we're outputting an image which creates a new byte array output stream.
The buffer capacity is initially 32 bytes, though its size increases if necessary.
So now we can use the bitmap and compress it.
So that's a function that Bitmaps has, and we need to pass in the format that we want to use to quality
and output streams.
So here?
What kind of format do we want to use while we can just use the bitmap compressed format?
So here just go ahead and use bitmap colon compress format.
So it's an item that we can use here.
And then I'm going to say I want to use the PMG format.
All right.
So the image will be stored as a peg.
Then you can say which quality you want to use.
And I'm going to say 90, which is 90 percent, which is a good enough quality.
Very good quality, actually.
So you don't want to overdo it because otherwise the image will just be huge, and I don't think it's
necessary for our application.
And then I'm just going to pass in the output stream.
So byte array output stream.
So Bytes is how I call this, but you could of course, call it differently.
And then now that we are compressing it, we need to create a file out of it so that we can store it
because we can now then used to file output stream.
So let's create a file.
And this will be a file which has a Perth name and can use the external cache directory.
Dot.
And a simple file for a second here or in a second.
OK, so we can get the external cache directory, then the absolute file to string.
So this will give us a location.
Where our application is, so to speak.
So this is going to be the path name which we now add something to.
OK, so this is where it will be on our device, so to speak global and to store the image.
And I'm going to add the file separator.
To it, which is also a string.
So this is the file separator, whatever is used as a file separator could be a dot or whatever, and
then I'm using the name of my application.
I'm just going to call this one case drawing.
Our case drawing app on the score, so you can call it whatever this will just be, how the file will
be called on my system.
And then in order to give each image a unique name, I'm just going to add the current time in milliseconds
divided by 1000 plus and then to type dot PNG.
OK.
So what will now happen is, well, this is basically going to be the location for the file and will
create a file item.
So we're passing where the location is and we're saying, OK, I want this file to be stored with the
name at this location.
And then.
We can create a file output stream.
So file output, stream object and pass our app to it.
So our file to it.
So now we just need to write.
So here let's use bytes thought to byte array so it will take our battery output stream and make about
a ray out of it.
And then we can close it.
So overall, we're creating the file output stream, were writing something and then were closing the
file output stream and release any system resources associated with the stream.
It's really important.
And then we get the actual result.
So here we can assign the result to be that absolute path.
So the absolute path of the file.
So basically, where to fight list and now we can run something on the UI threat because this is a suspend
function, write a code routine function, which means it will run all of this stuff in the background,
which is great.
That's exactly how you're supposed to do it.
Don't run this resource intensive stuff on the main thread on the UI thread.
But what we do want to run on the UI threat is going to be.
Letting the user know where the file was saved because it was saved and the result, right, so we can
just check if result.
That is not empty and it is not empty, so if it's not empty, then we want to write a toast and toast
will just be basically saying where the result is.
So make text file save successfully add result.
So this is the location where it has been stored for a short period of time and otherwise.
So in the case, if result is empty, we're going to say that something went wrong saving the file.
So another toast here.
Something went wrong while saving the file.
Now, because this all can go wrong, this entire try block.
Let's go ahead and add a catch block here, which we catch with an exception.
And we're just going to say in that case, result is going to be an empty string.
And we're going to print to the stack trace, whatever the error has in store for us.
And you see, we still have an error here because we need to return something and we need to return
a string.
And luckily enough result is in fact going to be a string.
So here the result will either be empty.
So it is empty at the beginning.
And in the case that there is an exception, we are really making sure that it's going to be empty.
And if there is no exception and things go right, we are trying to create this file.
And on the UI thread, we are also displaying the results.
And of course, the result will be the path of the file that we created.
So the image that we created.
OK, so now we have this safe bitmap file method.
We have this get bitmap from new method and we have only looked at code for over 20 minutes now.
So let's go ahead and actually make this run.
And in order to make it run, we need to go to the on create method because there I want to use my button,
so my save button and I'm going to call it button save, and it will be the image button safe that we
created in the last video, which is this image button that has this little save icon.
All right.
And then, of course, we need to use the I.B. safe here instead of the I.B. undo.
So let's do that and call a different method in here, so that will be the important part.
So what is it that we want to call?
Well, we want to call or basically we want to execute a call routine.
So what I want to do here is I want to check, can I write to the stories?
And let's go over here and see, OK, we have read external storage, but now let's add uses permission,
right?
External storage here as well.
Like so and then, of course, any we need to make changes to our permission request here.
So we asked for external storage only, but now we need to ask for the other.
One as well amid check for the down.
Well, we showed a Russian nail.
Here what we request storage permission.
OK, so here we have an array of permissions, and you see we have this to do had writing external storage
permission, I added that earlier here we need to go ahead and use manifester.
Permission dot, right?
External.
Or what is it?
Right?
External storage, yeah, that's a.
So how do I now find out if I have the right to read to the storage and basically in later versions
of Android and the latest versions of Android?
You don't need to ask for read and write permissions at the same time.
But we're just making sure that we have both for all the versions.
But what we can now do is we can just go ahead and say private fun is read storage allowed.
Which will return a Boolean, which will just let me know if we do have storage reading right or not.
So what we can do is we can create a variable, which will be the result, and I get it from the context,
composite check, self permission and I need to pass in the context as well as the permission that I
want to check if I have that.
And I can just say manifestantes permission thoughts, read external storage.
So this will give me the result.
And now I just need to return this result as a Boolean.
So return result is equal equal package manager.
Package manager Dot.
Permission granted.
OK, so what we're doing here is we are having an if clause, so to speak, so result will be either
permission granted or not granted, so it will return a true or false statement.
So we're checking for self permission, which will return permission granted or not granted, right?
So static int which returns an integer and permission granted.
What is the integer for that?
You see the permission granted integer is zero.
So if we get zero as a response from this method, call here where we check whether we have external
reading storage permission, then result will be zero and permission.
Granted, this also zero, so it will return true.
Otherwise, it will return false.
So now we can check if we have right or the right to read it from the storage, which also gives us
the right to right to the storage in the latest Android Studio versions and the Android versions.
So here we can just check if is read storage allowed and if that's the case, then I want to launch
my lifecycle scope.
So basically my call routine launch.
Like so and we need to import lifecycle scope here.
Let's do that.
We need to import launch and both of them will be added to here import lifecycle, scope, launch,
dispatcher's and with context.
So all of these here are the call routine related imports.
OK, so just make sure that you have them.
And also, if you don't understand what's up here, definitely check out the ratings demo that I created
a couple of lectures before so we can now get the image from our.
View.
So what view does it have the image?
So what is the view that contains all of the graphics that we have in here?
Well, let's look at it.
So we need to go over to our frame layout and you can see that our frame layout here exists of an image
view and a drawing view.
And a drawing view is our self-created view that we have built, right?
This class, which contains all of the drawing that we did ourselves.
And then it contains the image that we have as the background.
So what we want to do is we want to get this frame layout, which is itself also a view.
We want to get that.
And we want to send which it.
So put those two things together to image, view and whatever we drew.
And we want the stories because that's what all of the methods that we created were for, right?
So our gets bitmap from view, it takes a view.
And for example, we could present the frame layout here, and then it says it to the well, this saves
this bitmap that is created from this view you see here.
It creates a bitmap where passing it to the safe bitmap file, and this method then saves it in the
background.
So let's put all of this together because this is quite advanced stuff, I'd say.
So let's use our full drawing view.
And like so drawing view, which is a frame layout.
So we need to import frame layout here for this to work.
So import frame layout like so and then we can find it by its ID or Dot ID dot drawing view container.
That's how we called this frame layout, right.
This frame layout here, which contains the view and everything is going to be the right.
Item that we want to have, because now what we can do with this AFL drawing view, we can pass it to
our safe bitmap file, get bitmap from you.
Call so what I'm doing here is I'm calling this method, which will return a bitmap and then I'm passing
this bitmap to save bitmap from file.
Of course, you could have gone ahead and said, my bitmap is of type, bitmap is equal to and then
put this here in there and then passed the my bitmap variable.
That would have been fine as well.
If you want to put it into two lines, but of course, you can also just go ahead and do it in one line
and you don't need this line here.
OK, so let's test this as the moment of truth, a bunch of code that we have set up.
Let's see if we can actually store the image onto our device.
OK, so let me draw something safe, and you see, this is where it was stored.
So once again, storage emulated zero Android Datacom.
So it's all of this stuff that we have here like super a long path here.
External cache directory, absolute file to a string, then the file separator and then kid drawing
up.
So once again, just quickly you see it, says Kit Kids drawing up.
So here it's it didn't even say kit drawing app because it was still doing all of this part.
So it's quite a long path.
All right now, how do we get to the image?
Well, we need to go to files and then here as Dickie Android data and then select the path of our application.
So come the kids drawing app cache, and that's where it's stored all of those images.
So let's go back to the application and not the photos app, but to our drawing app, and then let me
select a different image.
Here, let me select Homer.
Like, so OK, then let me draw something.
On top of his head, then save this and go over to the cash folder and we will find our Homer Simpson
with this little bubble around his head.
And yeah, that's pretty much it.
So now you know how to store your image on to your device.
All right, so see you in the next video.