2

I'm writing an application that takes HTML pages and parses them to display on the screen. Specifically, this application pulls HTML from a message board and lists posts made by users.

The problem is that a lot of the content in posts are pictures in <img> tags, so I need to write a Html.ImageGetter to handle the downloading of the images.

My textView.setText() method will look like this:

myTextView.setText(Html.fromHtml(myText, new ImageGetter() {                 
        @Override
        public Drawable getDrawable(String source) {
        Drawable d;

        // Need to async download image here 

         return d;
        }
    }, null));

Doing this synchronously is trivial, but is there a suggested way to do this asynchronously so that it doesn't lock up my UI thread? I would also like to eventually build in caching of these images, but I imagine that would be pretty simple once the async downloading was there.

thedude19
  • 2,643
  • 5
  • 34
  • 43

4 Answers4

2

Doing this synchronously is trivial, but is there a suggested way to do this asynchronously so that it doesn't lock up my UI thread?

That will be difficult, perhaps impossible. You have to return something immediately. Even if that is a placeholder, you then have the challenge of how to replace the placeholder once the download is complete. Since you lack access to the ImageView rendering the image (if there is an ImageView), I don't know how you would arrange to replace the placeholder.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • I see what you mean. Could there be another way to display Html with tags scattered throughout? I've read a little about using a WebView, but didn't really want to have to put many WebViews as rows in a ListView. Any other suggestions are appreciated :) – thedude19 Feb 03 '11 at 15:44
  • @thedude19: `WebView` in `ListView` may be problematic due to scrolling. However, at the same time, the `` support in `Html.fromHtml()` seems aimed at local assets (e.g., converting emoticons into equivalent icons). Moreover, I am really skeptical that you want complete message board entries in a `ListView`, anyway, simply because they could be really long. I humbly suggest that you consider having your `ListView` show the first 3-4 lines of the post, plain text only, showing the full post in a `WebView` if they click on the `ListView` entry. – CommonsWare Feb 03 '11 at 15:52
  • @CommonsWare: Thanks for taking the time to respond. I will consider all of this while moving forward. – thedude19 Feb 03 '11 at 15:56
  • @CommonsWare: Any other advice for accomplishing this task? I'd really like to duplicate the feel of the message board by displaying images in the messages. What about doing it synchronously and caching the images locally on the device? This would also require an option to allow the user to turn off image downloading in the case of limited connectivity. – thedude19 Feb 07 '11 at 16:43
  • @thedude19: "What about doing it synchronously and caching the images locally on the device? " -- if by "synchronously" you mean actually getting the downloads in `ImageGetter`, your app will crash with an ANR, and the list will not scroll while downloads are occurring. You may wish to consider rendering the whole UI in a `WebView`. – CommonsWare Feb 07 '11 at 17:09
  • @CommonsWare: Yea, it seems as though web view is looking better and better. My thought for downloading in ImageGetter was to display some type of 'Loading...' screen until that page was downloaded. Maybe its best to try to work with WebView, even though it comes with its own issues I''m sure. – thedude19 Feb 07 '11 at 17:17
  • @thedude19: Another possibility would be to render the list entry immediately with a placeholder, and kick off the download in the background. When the image(s) are ready, you can replace the whole row with a freshly-rendered HTML, this time displaying the actual images. Doing that dynamically might cause issues for the user, but you could do it as part of normal row display when the user scrolls, or something. – CommonsWare Feb 07 '11 at 17:21
  • @CommonsWare: Yes, that is true, also. I'm seeing some good examples of background downloading and caching here: http://stackoverflow.com/questions/541966/android-how-do-i-do-a-lazy-load-of-images-in-listview that I may be able to incorporate. Thanks for all your help and responses. I'll keep you updated if you are interested. If I actually get something working nicely it may set up a nice opportunity for a blog post or something to show how to do it. – thedude19 Feb 07 '11 at 17:24
  • @CommonsWare: Hope you don't mind me yapping in your ear again :) So I was able to get a WebView to display (somewhat) properly in each row of my ListView. There seem to be some problems with this (web view wants to act like a browser, obviously) and also some bigger problems (like once i scroll around and load too many webviews the activity crashes back out to the previous activity). I'm sure this is due to memory issues since many webviews can be image heavy. I had another thought though. What if I pull down the http page for the current list of messages, and 'massage' that html... – thedude19 Feb 09 '11 at 18:26
  • @CommonsWare: and put in my own styling to 'mobilize' it. That way, my activity goes from being a ListView full of WebViews to a single WebView with a toolbar/menus/whatever else attached to it. Is there a way to use a local .css file in Android or would I just inject the styling into the HTML when processing it? Also would like your thoughts on if this idea is worthwhile. Thanks again :) – thedude19 Feb 09 '11 at 18:27
  • @thedude19: "That way, my activity goes from being a ListView full of WebViews to a single WebView with a toolbar/menus/whatever else attached to it." -- that's kinda what I meant by "You may wish to consider rendering the whole UI in a `WebView`" (see fifth comment from the top). "Is there a way to use a local .css file in Android or would I just inject the styling into the HTML when processing it?" -- either should work, though getting `WebView` to load local files is sometimes tricky. – CommonsWare Feb 09 '11 at 19:16
  • @CommonsWare: Oh man. All that and I come to the conclusion 'all by myself' to try it in a single WebView. Too funny. I really appreciate your help on this and taking the time to have a dialog. It's greatly appreciated. I'll be following your twitter and possibly checking out your books and blog. Thanks again. – thedude19 Feb 09 '11 at 19:25
  • @CommonsWare: Massaging the HTML and reconstructing it myself with my own styles (and I'm even using an external CSS file in my assets dir) is working WONDERFULLY. I'm getting great results and great performance and it should only get better as I tweak it. Thanks again for talking through this with me. – thedude19 Feb 10 '11 at 17:29
  • @thedude19 I using async solution for this and it's perfect https://stackoverflow.com/questions/63870726/spannable-text-that-holding-custom-view – Ibrahim Ali Mar 16 '21 at 21:10
1

I'd use either an AsyncTask or a Thread/Handler combination.

dave.c
  • 10,910
  • 5
  • 39
  • 62
  • I assume that the OP is familiar with AsyncTask et al, and is asking specifically how to do this with the `ImageGetter.getDrawable()` inside a `ListView`. See my related [question](http://stackoverflow.com/q/11712130/403455). – Jeff Axelrod Jul 30 '12 at 12:31
0

How about extract all the urls before displaying the html by using an invisible Html.fromHtml, putting those urls in a list, asynchronously downloading all images, storing them in an in memory cache, then implementing the ImageGetter to just do a cache lookup using the url as a key and the drawable as the value.

davidjnelson
  • 1,111
  • 12
  • 22
  • Wouldn't this proposal require that the entire list be downloaded and cached prior to displaying the `ListView`? If so, I'm not sure this is any better than doing it synchronously. – Jeff Axelrod Jul 30 '12 at 12:27
0

for downloading asynchronously the images and storing them in memory cache there is a mini-library here :) https://github.com/koush/UrlImageViewHelper

koush
  • 2,972
  • 28
  • 31
Vasile Surdu
  • 1,203
  • 1
  • 10
  • 11