others-How to show image in CDATA text in android applications?

1. Purpose

In this post, I would demo how to show an image in android application within a CDATA tag.

2. Environment

  • android studio 3.5

3. The solution

3.1 The problem

Suppose we have an app that shows a text in the main page:

image-20210801205631958

The text is defined in src/main/res/values/strings.xml in our android project, you can see that the text is defined in HTML foramt

<resources>
    <string name="test">
        <![CDATA[
  		    <h1><font color="red">title</red></h1>
        ]]>
    </string>
</resources>

The textview in the center of our app is initialized as follows:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        initText();
    }

    private void initText() {
        TextView tvTest = (TextView)this.findViewById(R.id.tvTest); //find the view
        tvTest.setText(Html.fromHtml(String.format(  //show the text in html format
                this.getString(R.string.test))));

    }

Now, How to do if we want to show an image in the textview?

3.2 The solution

First, we add an image file to src/main/res/drawable folder of our project:

app/src/main/res/
├── drawable
   ├── test.png

Then, we add an image tag in the CDATA of the title:

<resources>
    <string name="test">
        <![CDATA[
  		    <h1><font color="red">title</red></h1>
            <p><img src="test">The test image</p>
        ]]>
    </string>
</resources>

At last, we add code to show the image in the CDATA text:

private void initText() {
        TextView tvTest = (TextView)this.findViewById(R.id.tvTest);
        tvTest.setText(Html.fromHtml(String.format(
                this.getString(R.string.test)),new ImageGetter(),null));
    }

    class ImageGetter implements Html.ImageGetter {
        public Drawable getDrawable(String source) {
            int id;

            if (source.equals("test")) {
                id = R.drawable.test;
            }
            else {
                return null;
            }

            Drawable d = getResources().getDrawable(id);
            d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
            return d;
        }
    }

In the above code, we do the following jobs:

  • We created a Html.ImageGetter, which is responsible to retrieve the image by the image name
  • We call the Html.fromHtml() with three parameters including the string, the ImageGetter and a null.

Then we runt he app, we get this:

image-20210801212236538

3.3 Why it works?

According to this article, if you want to use html image tag in CDATA , you should use this function:

public static Spanned fromHtml (String source, 
                int flags, 
                Html.ImageGetter imageGetter, 
                Html.TagHandler tagHandler)

Returns displayable styled text from the provided HTML string. Any tags in the HTML will use the specified ImageGetter to request a representation of the image (use null if you don’t want this) and the specified TagHandler to handle unknown tags (specify null if you don’t want this).

This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.

The ImageGetter is responsible for the content of the image, the core function is:

public abstract Drawable getDrawable (String source)

This method is called when the HTML parser encounters an tag. The source argument is the string from the “src” attribute; the return value should be a Drawable representation of the image or null for a generic replacement image. Make sure you call setBounds() on your Drawable if it doesn’t already have its bounds set.

4. Summary

In this post, I demonstrated how to display an image inside a CDATA in android applications, the key point is to use the Html.fromHtml with Html.ImageGetter.