- Async Loading Images on Android Like a Big Baws
- An Approach For Dealing With Resources
- Make an AsyncTask
- Defining a Callback Listener
- Using it from a Presenter
- Adding a Simple Caching Layer
- Exploiting Parallelism
- Closing Thoughts
- Loading Image Asynchronously in Android ListView
- 2. What is Android AsyncTask
- 3. Downloading image using AsyncTask
- 4. Downloading image from web
- 5. Creating custom ListView
- 5.1. Adding ListView to activity layout
- 5.2. Create list view activity
- 5.3. Create list row layout
- 5.4. Creating custom list adapter
- 5.5. Using list view adapter
- Async image loading — The Jetpack Compose way
- Enter Jetpack Compose
- So let’s create an Image!
- Compose community
- Let’s build our custom widget!
Async Loading Images on Android Like a Big Baws
Mar 26, 2017 · 4 min read
I think probably the most appropriate content for an article with this title would be about using Rx with Glide. Anyway, this one isn’t. The main point of this is to “quickly do the thing” with out-of-box Android facilities, with a focus on maintainable code.
An Approach For Dealing With Resources
My general approach to dealing with Android views and presentation in general is basically like:
- Make the best use of the xml facilities that I can;
- In Java, use collections by default when dealing with resource ids;
- Try to use new source files where appropriate to prevent the Massive Activity anti-pattern (or more properly, the “ M assive V iew C ontroller” problem as better maps to the well-known acronym, and is dually relevant to iOS.)
As I see the former problem on a daily b a sis while I am trolling — nay, providing meaningfully to the community of — StackOverflow, I figured I would put this on the Internet. That it might thusly be searched upon one day, and in the eye of that very searcher then, be looked upon fondly.
Suppose you have an ImageView , and you want to populate it form content on the public Inter-tubes. The motivations for this could be several, but in general this is your only practical solution if you’re dynamically generating content and the range of possible content for the image is unbounded.
In my case, I was developing a toy application for the Medium Java SDK I have been working on. The capability I needed was to asynchronously load image content for the profile picture of a Medium user. Or in other words:
Like I mentioned previously — if you are developing this infrastructure, you might as well make it work on many things, not just a thing. Imagine there is no such thing as “a resource,” there are only “collections of resources.”
Make an AsyncTask
First let’s just setup some builder plate for a DownloadImageTask in a new file called DownloadImageTask.java . The task accepts String as input, which will be an URL to image on the Internet. As its output, it returns a Bitmap .
Okay, cool. Now we need a way to actually download an image:
Alright, not too bad, all we have to do is collect the thing in onPostExecute and be on our merry way. What I propose to do is actually add a new callback facility to our DownloadImageTask , which will allow a bit more flexibility and continue to keep our logic in this file and out of our Activity code.
Defining a Callback Listener
When we create a DownloadImageTask , let’s pass in a Listener , in its constructor:
Now, when the DownloadImageTask completes, we can inform the listener:
But what is a Listener ? It is an interface defined inside of the DownloadImageTask :
So, with this in place, we easily start new tasks from our presentation logic and download a bunch of images, getting notified when they are ready.
Using it from a Presenter
Now, back in your presenter, where you started to define your presentation logic (e.g. “Attach this view to this image resource according to Business Rule 44§A11”)
All that is left is to add the logic to bind views and downloaded images:
And there you have it. A fairly lightweight way to Async-load images into all of the ImageView s in your view.
Adding a Simple Caching Layer
This has some limitations. For one, there’s no caching. So, depending on your application’s logic, all of the resources have to be retrieved again when you rotate the screen. A naive solution to that would be to add an additional field in your Application class, like:
Then in your doInBackground() , first check if there is a bitmap already in the cache, something like:
Even better would be write the images out to disk at the end of doInBackground() , and try to retrieve them from disk at the beginning of doInBackground() .
Really though, you should probably use Glide at this point for any project of complexity.
Exploiting Parallelism
This is a great use case for doing several things at once. You don’t care about the order in which your images load, you just want them to load quickly.
Due to the way a default AsyncTask is setup, the code above would execute each task one after the other, from a queue. It is still asynchronous from your perspective, it’s just that the actual time it takes to download many images could be improved.
To run them in parallel, execute each AsyncTask on a thread pool:
(See also Java 7 docs on ThreadPoolExecutor .)
Closing Thoughts
This approach would work well if you have a relatively small number of images in your application and/or do not want to take on additional dependencies.
If you have a whole bunch of images, or are incrementally loading them via a scrolling view, then you’ll probably want to bring in the Big Guns. Intelligent caching will increasingly be important as the number of images rises.
Anyway, hopefully this is useful to someone. Enjoy!
Источник
Loading Image Asynchronously in Android ListView
As mobile devices are limited with memory, we must follow certain best practices to provide best performance and smooth user experience. Among set of best practices, the one holds priority is to take the long running heavy operations off the main thread.
Any long running tasks or heavy operations are usually performed in a different thread, to make sure your main thread does the minimum amount of work. Example of a typical long running tasks could be network operations, reading files form memory, animations, etc.
In this tutorial, we will create a simple ListView in Android that downloads data asynchronously from the internet using a AsyncTask. As you can see in the screenshot below, the ListView contains a image thumbnails on each row, we will download the images asynchronously form server.
If you’re looking for downloading data from asynchronously from server, we recommend you to read through Android networking tutorial.
2. What is Android AsyncTask
AsyncTask enables you to implement MultiThreading without getting your hands dirty into threads. AsyncTask is easy to use, and it allows performing background operation in dedicated thread and passing the results back UI thread. If you are doing something isolated related to UI, for example downloading data for List view, go ahead and use AsyncTask. Some of the basic characteristics of AsyncTask are as follows
- An asynchronous task is defined by 3 generic types, called Params , Progress and Result , and 4 steps, called onPreExecute , doInBackground , onProgressUpdate and onPostExecute .
- In onPreExecute you can define code, which need to be executed before background processing starts.
- The doInBackground() method contains the code which needs to be executed in background, here in doInBackground we can send results to multiple times to event thread by publishProgress() method, to notify background processing has been completed we can return results simply.
- The onProgressUpdate() method receives progress updates from doInBackground method, which is published via publishProgress method, and this method can use this progress update to update event thread
- The onPostExecute() method handles results returned by doInBackground method.
- If an async task not using any types, then it can be marked as Void type.
- An running async task can be cancelled by calling cancel() method.
The generic types used by AsyncTask are
- Params, the type of the parameters sent to the task upon execution
- Progress, the type of the progress units published during the background computation.
- Result, the type of the result of the background computation.
3. Downloading image using AsyncTask
We had learnt the basics of AsyncTask. Let us take a glance at how to use it practically for downloading image asynchronously from web. To achieve this, let us create a new class and name it as ImageDownloaderTask .
The following code snippet expects the url of image as an parameter and initiate download image download request. Once download is over, it displays the bitmap on the image view.
4. Downloading image from web
Notice that, in the above step we are calling downloadBitmap() method but haven’t declared it yet. Let us create declare the downloadBitmap method which takes care of loading image and returning the bitmap. Here we are using HttpURLConnection to download the stream from given url. Learn more about HttpURLConnection from our android networking tutorial.
5. Creating custom ListView
Now that we understand the basics of AsyncTask, let us proceed with creating the custom list view in android. The focus of this tutorial is tried to image download. If you not familiar with creating custom list view in android, you can read our Android ListView tutorial.
5.1. Adding ListView to activity layout
For sake of simplicity our activity layout contains a simple ListView that covers the total available width and height of the device. Create a new file activity_main.xml in layout directory.
5.2. Create list view activity
Let us now create a new activity class MainActivity.java in your project src directory and paste the following code. We will complete this activity in Section 3.5
5.3. Create list row layout
Now let us focus on the layout for list view row item. As you can notice form the above screenshot, we will use RelativeLayout for building a simple list row view. Crete a new file list_row_layout.xml file in layout directory and paste the following code blocks.
5.4. Creating custom list adapter
Adapter is acts as a bridge between data source and adapter views such as ListView, GridView. Adapter iterates through the data set from beginning till the end and generate Views for each item in the list.
Create a new class named CustomListAdapter and extend it from BaseAdapter. Visit here to learn more about android adapters.
5.5. Using list view adapter
Now that we have the list view and adapter class ready. Let us proceed to complete the MainActivity class. The following code snippet is used to initialize the list view and assign the custom adapter to it.
Источник
Async image loading — The Jetpack Compose way
Being an Android developer is a wonderful and frustrating position to be in.
On the one hand, we can create amazing apps, design our logic in a coherent, elegant codebase, and let our users enjoy the show.
On the other hand, if you ask experienced Android developers about what are the pain points of Android development, most would provide the same answer.
Building UI’s using that infamous XML file.
Enter Jetpack Compose
Jetpack Compose is a new, declarative way of writing UI code in Kotlin for Android, there are a lot of resources on the issue, I would recommend this video by Leland Richardson, one of the main engineers on the Android toolkit team, and there are some great code labs to follow as well.
So let’s create an Image!
All UI components in Compose are widgets, and widgets are basically functions annotated with Composable annotation.
similar to the suspend keyword in Kotlin, composable functions can only be called from other composable functions, more on that in this video.
Let’s see a basic widget in Compose:
As we can see, this is a widget that displays an image with a drawable resource.
But wait… most of the images I might be displaying in my app would be loaded from a network, that is asynchronous work, I have great libraries to handle that in the Android view system, but how the h**l am I gonna do that in Compose?!
Compose community
Luckily, the Compose community is amazing and I came across a post on the #compose slack channel by Leland Richardson, and finally, I had a good direction.
For this widget we use Picasso, but any other image loading library can do it, as long as it provides a Target interface for us to load the image into.
To incorporate Picasso in your Android app, add the following dependency in your build.gradle file:
Let’s build our custom widget!
First, we start, as always, with a function, annotated with the Composable annotation.
When loading a URL to an image using an image loader we usually need a reference to a view where the image can be viewed at but in Compose, we have no views, so where would we load the image to?
Picasso and most other image loaders have some sort of a Target interface, which provides callbacks such as onSuccess and onFail. in Picasso, that interface looks like this:
We can see that using this interface we can get a bitmap of the loaded image when it is loaded, a drawable of the error state with the error itself if a failure happens and a drawable for the placeholder if we provide one for Picasso.
Now its time to use a new fancy tool provided by the Compose framework, it is calls the onCommit lambda.
The onCommit effect is a lifecycle effect that will execute callback every time the inputs to the effect have changed.
Sounds complicated… so let’s simplify!
Basically, this is a lambda that takes an argument and provides a scope in which you can run your code, and dispose of it when needed, this is very handy when dealing with asynchronous operations like downloading an image from the internet.
We can use it like this:
Wow… That’s a lot of code to take in… let’s explain:
First, we declare remembered values, an image asset, which we will obtain from the network. and a drawable, which will be a placeholder or an error image and would be obtained by us from our app resources.
They will help us maintain state through recomposition.
Learn more about remember keyword and states in Jetpack Compose here.
Then we declare the onCommit lambda that will provide a scope in which we can execute our asynchronous code:
We also dealt with placeholder and failure in our code and we also need to handle disposal for the code in this block.
And lastly, we can load the image we have obtained into the target:
So once we exit the onCommit block, we now have an image and a drawable, and we can finally compose our widget:
And if we want a placeholder image until the image is ready, or some error drawable in case of failure, we add this code to draw it on a Canvas widget:
And that’s it! we now have a widget that can download an image from the network and show it! the full code widget is:
Thank you for reading!
And hope you create amazing complex widgets yourselves in no time!
Источник