DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • How to Build a React Native Chat App for Android
  • Using Jetpack Compose With MVI Architecture
  • Implementing SOLID Principles in Android Development

Trending

  • System Coexistence: Bridging Legacy and Modern Architecture
  • How to Convert XLS to XLSX in Java
  • Introduction to Retrieval Augmented Generation (RAG)
  • Useful System Table Queries in Relational Databases
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Deployment
  4. Dynamically Loading Recycler View Images in Android

Dynamically Loading Recycler View Images in Android

Learn how thumbnail images in the table views of Android mobile apps can be loaded dynamically as needed to populate recycler view cells.

By 
Greg Brown user avatar
Greg Brown
·
Jul. 17, 17 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
95.1K Views

Join the DZone community and get the full member experience.

Join For Free

as in ios , android applications often display thumbnail images alongside other text-based content such as contact names or product descriptions in recycler views. however, the images are not usually delivered with the initial request, but are instead retrieved separately afterward. they are typically downloaded in the background as needed to avoid blocking the ui thread, which would temporarily render the application unresponsive.

for example, consider this sample rest service , which returns a list of simulated photo data:

[
  {
    "albumid": 1,
    "id": 1,
    "title": "accusamus beatae ad facilis cum similique qui sunt",
    "url": "http://placehold.it/600/92c952",
    "thumbnailurl": "http://placehold.it/150/92c952"
  },
  {
    "albumid": 1,
    "id": 2,
    "title": "reprehenderit est deserunt velit ipsam",
    "url": "http://placehold.it/600/771796",
    "thumbnailurl": "http://placehold.it/150/771796"
  },
  {
    "albumid": 1,
    "id": 3,
    "title": "officia porro iure quia iusto qui ipsa ut modi",
    "url": "http://placehold.it/600/24f355",
    "thumbnailurl": "http://placehold.it/150/24f355"
  },
  ...
]

each record contains a photo id, album id, and title, as well as urls for both thumbnail and full-size images; for example:

photo class

a class representing this data might be defined as follows:

public class photo {
    private number id;
    private number albumid;
    private string title;
    private url url;
    private url thumbnailurl;

    public photo(map<string, ?> map) {
        id = valueat(map, "id");
        albumid = valueat(map, "albumid");
        title = valueat(map, "title");

        string url = valueat(map, "url");
        string thumbnailurl = valueat(map, "thumbnailurl");

        try {
            this.url = new url(url);
            this.thumbnailurl = new url(thumbnailurl);
        } catch (malformedurlexception exception) {
            throw new runtimeexception(exception);
        }
    }

    public int getid() {
        return id.intvalue();
    }

    public int getalbumid() {
        return albumid.intvalue();
    }

    public string gettitle() {
        return title;
    }

    public url geturl() {
        return url;
    }

    public url getthumbnailurl() {
        return thumbnailurl;
    }
}

the constructor extracts property data from a map instance using the static valueat() method of the http-rpc webserviceproxy class. instances of this class will be used later to retrieve the photo list as well as the thumbnails themselves.

main activity class

a basic user interface for displaying service results in a recycler view is shown below:

the markup for the main activity simply declares an instance of recyclerview that will occupy the entire screen:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.recyclerview android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"/>
</linearlayout>

item markup is shown below:

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="16dp">
    <imageview android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <textview android:id="@+id/text_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginleft="8dp"/>
</linearlayout>

view holder and adapter classes are used to produce and configure individual photo item views. item data is stored in a list of photo instances, and previously loaded thumbnail images are stored in a map that associates bitmap instances with photo ids. the executor service will be used later by webserviceproxy to execute service requests:

public class mainactivity extends appcompatactivity {
    // photo view holder
    private class photoviewholder extends recyclerview.viewholder {
        ...
    }

    // photo adapter
    private class photoadapter extends recyclerview.adapter<photoviewholder> {
        ...
    }

    private recyclerview recyclerview;

    private arraylist<photo> photos = null;

    private hashmap<integer, bitmap> photothumbnails = new hashmap<>();

    private executorservice executorservice = executors.newsinglethreadexecutor();

    private static string tag = mainactivity.class.getname();

    ...
}

when the activity is created, the view is loaded and the recycler view configured:

@override
protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);

    setcontentview(r.layout.activity_main);

    recyclerview = (recyclerview)findviewbyid(r.id.recycler_view);

    recyclerview.setlayoutmanager(new linearlayoutmanager(this));
    recyclerview.setadapter(new photoadapter());
}

the photo list is loaded the first time the activity resumes. an instance of webserviceproxy is used to retrieve the data. if the call succeeds, the response data (a list of map objects) is transformed into a list of photo objects and the recycler view is refreshed. otherwise, an error message is logged:

@override
protected void onresume() {
    super.onresume();

    // load photo data
    if (photos == null) {
        url serverurl;
        try {
            serverurl = new url("https://jsonplaceholder.typicode.com");
        } catch (malformedurlexception exception) {
            throw new runtimeexception(exception);
        }

        webserviceproxy serviceproxy = new webserviceproxy(serverurl, executorservice) {
            @override
            protected void dispatchresult(runnable command) {
                runonuithread(command);
            }
        };

        serviceproxy.invoke("get", "/photos", (list<map<string, ?>> result, exception exception) -> {
            if (exception == null) {
                photos = new arraylist<>(result.size());

                for (map<string, ?> value : result) {
                    photos.add(new photo(value));
                }

                recyclerview.getadapter().notifydatasetchanged();
            } else {
                log.e(tag, exception.getmessage());
            }
        });
    }
}

note that the service proxy overrides dispatchresult() to ensure that the response handler is executed on the ui thread.

item content is managed by the view holder and adapter classes. the corresponding photo instance is retrieved from the photos list and used to configure the item view:

private class photoviewholder extends recyclerview.viewholder {
    private imageview imageview;
    private textview textview;

    public photoviewholder(view view) {
        super(view);

        imageview = (imageview)view.findviewbyid(r.id.image_view);
        textview = (textview)view.findviewbyid(r.id.text_view);
    }
}

private class photoadapter extends recyclerview.adapter<photoviewholder> {
    @override
    public photoviewholder oncreateviewholder(viewgroup parent, int viewtype) {
        return new photoviewholder(layoutinflater.from(parent.getcontext()).inflate(r.layout.item_photo, parent, false));
    }

    @override
    public void onbindviewholder(photoviewholder holder, int position) {
        photo photo = photos.get(position);

        // attempt to load image from cache
        bitmap thumbnail = photothumbnails.get(photo.getid());

        if (thumbnail == null) {
            // image was not found in cache; load it from the server

            ...
        } else {
            holder.imageview.setimagebitmap(thumbnail);
        }

        holder.textview.settext(photo.gettitle());
    }

    @override
    public int getitemcount() {
        return (photos == null) ? 0 : photos.size();
    }
}

if the thumbnail image is already available in the cache, it is used to populate the item's image view. otherwise, it is loaded from the server and added to the cache as shown below. if the item is still visible when the image request returns, it is updated immediately:

// image was not found in cache; load it from the server
url thumbnailurl = photo.getthumbnailurl();

url serverurl;
try {
    serverurl = new url(string.format("%s://%s", thumbnailurl.getprotocol(), thumbnailurl.gethost()));
} catch (malformedurlexception exception) {
    throw new runtimeexception(exception);
}

webserviceproxy serviceproxy = new webserviceproxy(serverurl, executorservice) {
    @override
    protected object decodeimageresponse(inputstream inputstream, string imagetype) {
        return bitmapfactory.decodestream(inputstream);
    }

    @override
    protected void dispatchresult(runnable command) {
        runonuithread(command);
    }
};

serviceproxy.invoke("get", thumbnailurl.getpath(), (bitmap result, exception exception) -> {
    photothumbnails.put(photo.getid(), result);

    // if view is still visible, update image
    photoviewholder viewholder = (photoviewholder)recyclerview.findviewholderforadapterposition(position);

    if (viewholder != null) {
        viewholder.imageview.setimagebitmap(result);
    }
});

summary

this article provided an overview of how images can be dynamically loaded as needed to populate recycler views in android. for more information, please see the http-rpc project on github.

Android (robot)

Published at DZone with permission of Greg Brown, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • How to Build a React Native Chat App for Android
  • Using Jetpack Compose With MVI Architecture
  • Implementing SOLID Principles in Android Development

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!