Kotlin uses TextView to load Html tags (with Web picture links in the tags)

I have been engaged in Android development for some time. I used to develop in native or mixed mode. Recently, I came across a relatively new development mode, and I used Kotlin for App development. Let's get to know Analysis of advantages and disadvantages of android native application, Web application and hybrid application , Kotlin tutorial: https: //www.runoob.com/kotlin/kotlin-tutorial.html . One of the function modules needs to load the Html tag obtained from the network to display the details of the product, and the function UI is as shown in the figure:

HTML tag, as shown:

There are two ways to load Html, one is WebView, the other is TextView.

[1] TextView load Html tag:

Call the interface Html.ImageGetter and override the getdrawable (source: String) method:

/**
 * Get pictures
 */
override fun getDrawable(source: String): Drawable {
    val d = LevelListDrawable()
    //Set default picture
    val empty = mContext.getResources().getDrawable(R.mipmap.product_def_small)
    d.addLevel(0, 0, empty)
    //Specify a boundary for the drawn graph (getScreenWidth(mContext) gets the screen width, getinsideheight() gets the height of the picture drawn)
    d.setBounds(0, 0, getScreenWidth(mContext), empty.getIntrinsicHeight())
    //Call to load inner class asynchronously
    mLoadImageTask=LoadImageTask();
    mLoadImageTask!!.execute(source, d)
    //Add asynchronous objects to the collection for easy destruction
    mLoadImageTasks.add(mLoadImageTask!!);
    return d
}

//Inherit AsyncTask, rewrite: doinbackground (vararg params: any), onCancelled(), onpostexecute (bitmap?)
/**
**doInBackground()Be responsible for converting the obtained pictures into Bitmap
/
override fun doInBackground(vararg params: Any): Bitmap? {
    val source = params[0] as String
    mDrawable = params[1] as LevelListDrawable
    try {
        val `is` = URL(source).openStream()
        Timber.i(javaClass.name+"doInBackground======"+isCancelled);
        //Executing isCancelled method after AsyncTask cancel call
        if(isCancelled)
            return null;
        return BitmapFactory.decodeStream(`is`)
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    } catch (e: MalformedURLException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
    return null
}
override fun onCancelled() {
    super.onCancelled()
    Timber.i(javaClass.name+"onCancelled======");
}
/**
 * Execute after picture download
 */
override fun onPostExecute(bitmap: Bitmap?) {
    Timber.i(javaClass.name+"onPostExecute======");
    if (bitmap != null) {
        val d = BitmapDrawable(bitmap)
        mDrawable!!.addLevel(1, 1, d)
        /**
         * Fit picture size 
         * Default size: bitmap.getWidth(), bitmap.getHeight()
         * Adaptation screen: getDrawableAdapter
         */
        mDrawable = getDrawableAdapter(mContext, mDrawable!!, bitmap.width, bitmap.height)
        // mDrawable.setBounds(0, 0, bitmap.getWidth(),
        // bitmap.getHeight());
        mDrawable!!.level = 1
        /**
         * Reassign textView after image download          
         */
        mTextView.invalidate()
        val t = mTextView.getText()
        mTextView.setText(t)
    }
}
/**
 * Load network picture, fit size
 *
 * @param context
 * @param drawable
 * @param oldWidth
 * @param oldHeight
 * @return
 */
fun getDrawableAdapter(context: Context,drawable : LevelListDrawable, oldWidth: Int, oldHeight: Int): LevelListDrawable {
    var newHeight: Long = 0// Unknown number
    val newWidth = getScreenWidth(context)// Default screen width
    newHeight = (newWidth * oldHeight / oldWidth).toLong()
    // LogUtils.w("oldWidth:" + oldWidth + "oldHeight:" +
    // oldHeight);
    // LogUtils.w("newHeight:" + newHeight + "newWidth:" +
    // newWidth);
    drawable.setBounds(0, 0, newWidth, newHeight.toInt())
    return drawable
}
/**
 * Get screen width
 */
fun getScreenWidth(mC: Context) : Int{
    val wm = mC.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    val width = wm.defaultDisplay.width
    return width;
}

Finally, load the network to get the Html tag. In addition, you need to execute multiple AsyncTask destroy calls in the Activity onDestroy() method, cancleLoadImageTask().

.................
htmlImageGetter = HtmlImageGetter(mContext,tvImgContentDetail);
val spanned = Html.fromHtml(t?.wap_desc, htmlImageGetter, null)
tvImgContentDetail.setText(spanned)
fun cancleLoadImageTask(){
    for (i : Int in mLoadImageTasks.indices) {
        Timber.i(javaClass.name + "cancleLoadImageTask==="+(mLoadImageTasks[i]== null)+mLoadImageTasks.size)
        //you may call the cancel() method but if it is not handled in doInBackground() method
        if (mLoadImageTasks[i] != null && mLoadImageTasks[i].getStatus() != AsyncTask.Status.FINISHED) {
            mLoadImageTask!!.cancel(true)
            mLoadImageTasks.remove(mLoadImageTasks[i]);
        }
    }
}

Full code:

package com.midai.goodbabymall.util

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LevelListDrawable
import android.os.AsyncTask
import android.text.Html
import android.view.WindowManager
import android.widget.TextView
import com.midai.goodbabymall.R
import timber.log.Timber
import java.io.FileNotFoundException
import java.io.IOException
import java.net.MalformedURLException
import java.net.URL
import java.util.*


class HtmlImageGetter(mC: Context, mTv: TextView) : Html.ImageGetter {

    private var mContext: Context
    private val mTextView: TextView
    private var mLoadImageTask : LoadImageTask?=null;
    private var mLoadImageTasks= mutableListOf<LoadImageTask>();

    init {
        this.mContext = mC;
        this.mTextView = mTv;
    }

    /**
     * Get pictures
     */
    override fun getDrawable(source: String): Drawable {
        val d = LevelListDrawable()
        val empty = mContext.getResources().getDrawable(R.mipmap.product_def_small)
        d.addLevel(0, 0, empty)
        d.setBounds(0, 0, getScreenWidth(mContext), empty.getIntrinsicHeight())
        mLoadImageTask=LoadImageTask();
        mLoadImageTask!!.execute(source, d)
        mLoadImageTasks.add(mLoadImageTask!!);
        return d
    }

    fun cancleLoadImageTask(){
        for (i : Int in mLoadImageTasks.indices) {
            Timber.i(javaClass.name + "cancleLoadImageTask==="+(mLoadImageTasks[i]== null)+mLoadImageTasks.size)
            //you may call the cancel() method but if it is not handled in doInBackground() method
            if (mLoadImageTasks[i] != null && mLoadImageTasks[i].getStatus() != AsyncTask.Status.FINISHED) {
                mLoadImageTask!!.cancel(true)
                mLoadImageTasks.remove(mLoadImageTasks[i]);
            }
        }
    }

    /**
     * Asynchronous download picture class
     */
    internal inner class LoadImageTask : AsyncTask<Any, Void, Bitmap>() {

        private var mDrawable: LevelListDrawable? = null

        override fun doInBackground(vararg params: Any): Bitmap? {
            val source = params[0] as String
            mDrawable = params[1] as LevelListDrawable
            try {
                val `is` = URL(source).openStream()
                Timber.i(javaClass.name+"doInBackground======"+isCancelled);
                if(isCancelled)
                    return null;
                return BitmapFactory.decodeStream(`is`)
            } catch (e: FileNotFoundException) {
                e.printStackTrace()
            } catch (e: MalformedURLException) {
                e.printStackTrace()
            } catch (e: IOException) {
                e.printStackTrace()
            }
            return null
        }

        override fun onCancelled() {
            super.onCancelled()
            Timber.i(javaClass.name+"onCancelled======");
        }

        /**
         * Execute after picture download
         */
        override fun onPostExecute(bitmap: Bitmap?) {
            Timber.i(javaClass.name+"onPostExecute======");
            if (bitmap != null) {
                val d = BitmapDrawable(bitmap)
                mDrawable!!.addLevel(1, 1, d)
                /**
                 * Fit picture size 
                 * Default size: bitmap.getWidth(), bitmap.getHeight()
                 * Adaptation screen: getDrawableAdapter
                 */
                mDrawable = getDrawableAdapter(mContext, mDrawable!!, bitmap.width, bitmap.height)
                // mDrawable.setBounds(0, 0, bitmap.getWidth(),
                // bitmap.getHeight());
                mDrawable!!.level = 1

                /**
                 * Reassign textView after image download
                 *
                 */
                mTextView.invalidate()
                val t = mTextView.getText()
                mTextView.setText(t)
            }
        }

        /**
         * Load network picture, fit size
         *
         * @param context
         * @param drawable
         * @param oldWidth
         * @param oldHeight
         * @return
         */
        fun getDrawableAdapter(context: Context,drawable : LevelListDrawable, oldWidth: Int, oldHeight: Int): LevelListDrawable {
            var newHeight: Long = 0// Unknown number
            val newWidth = getScreenWidth(context)// Default screen width
            newHeight = (newWidth * oldHeight / oldWidth).toLong()
            // LogUtils.w("oldWidth:" + oldWidth + "oldHeight:" +
            // oldHeight);
            // LogUtils.w("newHeight:" + newHeight + "newWidth:" +
            // newWidth);
            drawable.setBounds(0, 0, newWidth, newHeight.toInt())
            return drawable
        }
    }

    /**
     * Get screen width
     */
    fun getScreenWidth(mC: Context) : Int{
        val wm = mC.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val width = wm.defaultDisplay.width
        return width;
    }

}

Keywords: Android Java network

Added by LiamOReilly on Wed, 01 Jan 2020 12:12:06 +0200