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; } }