TextView with HTML content with Images

Handling HTML content on a TextView is simple as far as the HTML coming in contains a few tags that are by default supported by Android. Simple formatting like bold, italics, font sizes can be handled without even coding a single extra line.

Say, if you have a TextView tv, and there’s some HTML string with bold and italicized text, bringing it up on the TextView is pretty simple.

One line code for that:

tv.setText(Html.fromHtml(source)); 

where the source is actually your HTML string. This works perfectly. But how do we show images if there are any. Well, it’s a bit tricky. You have to use the other method that takes in an ImageGetter and a TagHandler.

fromHtml(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler)

The tagHandler is for situations where you wish to handle specific tags differently. I didn’t wish to do that, so I just passed null there.

Now comes the main task. How do you get the image on to the TextView!!!!

Implement the Html.ImageGetter’s getDrawable method which handles downloading the image, or accessing it from the net, and then create a drawable and return that object.

      static ImageGetter imgGetter = new Html.ImageGetter() {
             @Override
             public Drawable getDrawable(String source) {
                   Drawable drawable = null;
                   drawable = Drawable.createFromPath(source);  // Or fetch it from the URL
                   // Important
                   drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable
                                 .getIntrinsicHeight());
                   return drawable;
             }
      };

and use the method on the TextView like this.
tv.setText(Html.fromHtml(source, imgGetter, null);

This will load the TextView with the image. But this call to the getDrawable method is not asynchronous. So, until and unless that method returns, you UI will be blocked. In my case, I am creating the drawable from a local image, so, it didn’t take much time. But, if you want to fetch an image from the web, you have to make this call in a separate thread, so that the UI is not blocked.

So, check your HTML string if they contain any images that have to be downloaded. If you find any, create a thread that download that image, saves it somewhere and returns you the location of that file. Now, change the src tags to point to the local images, and call setText method on the TextView.

And that should do it. The important thing to remember is, you have to change the HTML to point it to the file that you have downloaded.

Sample Source code : http://code.google.com/p/myandroidwidgets/source/browse/#svn/trunk/TextViewHTML 

This sample doesn’t use threads. So, your UI will be blocked unitl the image here is downloaded. So, keep waiting. πŸ™‚

52 thoughts on “TextView with HTML content with Images

  1. sasikumar

    Kumar,

    In my last comment i mentioned its working fine. After i posted comment & i tried to execute one more time, it showed same error Null Pointer Exception in setBound Line…

    Actually the drawable returns as null, so we can't able to set Bounds for that image.

    What's wrong with my code ?…

  2. Kumar Bibek

    By, code, I meant, Java code πŸ™‚
    What I can guess, would be your problem, is the formatting. Re-creating an image from a byte stream is difficult. So, I would suggest that you create files and use those files to create drawables.

  3. sasikumar

    Hi Kumar,
    When i try to use the code. I got the exception.
    Exception = java.io.FileNotFoundException: /sdcard/test.jpg

    When i created Emulator i didn't mentioned any size of SD Card. In my android Phone also i'm not having SD Card.
    This problem is due to SD Card ? , If so please give another idea without SD Card to load image in textview..

  4. sasikumar

    When i try to use getDataDirectory() it throws Excpetion.
    Exception = java.io.FileNotFoundException: /data/test.jpg

    I changed getDataDirectory() in both places.

    FileOutputStream fileout = new FileOutputStream(new File(Environment.getDataDirectory().getAbsolutePath()+ "/test.jpg"));

    drawable = Drawable.createFromPath(Environment .getDataDirectory().getAbsolutePath() + "/test.jpg");

  5. sasikumar

    Problem arise at the line

    drawable = Drawable.createFromPath(Environment .getDataDirectory().getAbsolutePath() + "/test.jpg");

    Before this line… I set

    FileOutputStream fileout = new FileOutputStream(new File(Environment.getDataDirectory().getAbsolutePath()+ "/test.jpg"));

  6. sasikumar

    Kumar… Thanks for your reply…
    I replaced my code with your code.
    Previously it thrown File not found exception… Now its throwing Unknown host exception.. I think its due to net problem ( Net speed is very low here). Tomorrow i will check it one more time & then i will reply to you about this..

    Once again thanks for your reply & answer.. πŸ™‚

  7. sjanamca

    Hi Kumar,
    Your code works fine. But when tried running it in thread it throws this exception

    "Exception=android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."

    Kindly give some hint what causing it.

  8. long

    thanks for your post.I'm trying to use Html.fromHtml, but I can not apply color for my text in textView, and I dont know how to insert image from local like you've said. Could you give me an example to solve two problems here, please?

  9. Anonymous

    Hello Kumar,

    I was just wondering if you have any idea about my problem. When I use getExternalStorageDirectory() it is able to create a temporary file but if I replaced it with getDataDirectory() I am able to retrieve the path but an error occurs when I create the
    temporary file. Can you help me with this? Thank you so much..

    File sampleDir = Environment.getExternalStorageDirectory();

    try {
    audiofile = File.createTempFile("test", ".3gp", sampleDir);
    }

  10. Anonymous

    Hello Kumar,

    Thanks for your quick reply..

    > For access to your package's data directory,
    > you have to append "/data/" to this path.

    File sampleDir = Environment.getDataDirectory();

    try {
    audiofile = File.createTempFile("test", ".3gp", sampleDir);
    }

    upon checking sampleDir is already equal to "/data" , do I still need to append "/data/" when calling createTempFile?

    If yes, I tried passing the following arguments instead
    File.createTempFile("/data/test", ".3gp", sampleDir)

    and it still didn't work..

    upon checking both values of AudioFile is null..

    Sorry, but I'm still new to Android programming..
    Thanks again.. Hope you can help me on this one.

  11. Kumar Bibek

    You data directory would be /data/data/. This is the complete path to your packages data directory. So, yes, you will have to not only append /data, but also your package name. For example, if your package name is com.sample, then your code should be like this.

    File file = new File(Environment.getDataDirectory().getAbsolutePath()+"/data/com.sample/test.jpg");

    Try this, this should work.

  12. long

    Thanks so much, now I'm using webview to show picture and rich text data. But it turns out to be very slow whenever I append text, and reload all the html content. I still want to use textView with image, for example chat with emoticon, hix, how to do that?
    Hope you can help me.

  13. Kumar Bibek

    Well, emoticons are different. Except those, you can show any HTML content on a TextView, of course, except videos. I have not done a performance comparison between the two, so I can't really comment if you are better off using TextView instead of WebView. You can ask your question on google groups, and someone will answer for sure.

  14. long

    Ok, thanks, using webview is the worst method I use to display image and text in a view, because I must reload all the data whenever I add new content. So that, thanks, I'm still finding out a way to display text and image. Thanks so much:D

  15. Anonymous

    Hello Kumar,

    Thank you very much!!

    Now I understand how it works. And also the code worked..
    >File file = new >File(Environment.getDataDirectory().getAbsolutePath()+"/data/com.sample/test.jpg");

    Thank you again..

  16. parul

    Hi Kumar,
    I want to get path of a file "accounts.db" which exists at path "/data/system/accounts.db".

    can you please suggest how should i use getDataDirecoty() in this case.
    i can hardcode till "/data" after that i want any function wich would search this file.

    any help wud be appreciable.

  17. m Aji

    you don't have to save the image locally first, you can use Drawable.createFromStream(inputStream, source) method, i have tried it, it works ! πŸ˜€ πŸ˜€ πŸ˜€

  18. vibhuti

    Hi.I tried using this in an edit text but encountered the following problems
    1)When i try to enter a second image the first disappears.
    2)The focus returns to the start of the edit text after inserting the image

Leave a Reply