Html.ImageGetter TextView

JMP*_*JMP 10 java android textview

所以我使用ImageGetter来显示JSON博客文章中的图像.我在日志中获取了正确的源,但是当URL达到setBounds时URL会发生变化.有任何想法吗?

码:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_blog_view);

    Intent intent = getIntent();
    Uri blogUri = intent.getData();
    mPost = blogUri.toString();
    mUrl = getIntent().getStringExtra("mUrl");

    TextView textView = (TextView) findViewById(R.id.scrollView1);
    textView.setText(Html.fromHtml(mPost, imgGetter, null));
}

private ImageGetter imgGetter = new ImageGetter(){
    @Override
    public Drawable getDrawable(String source){
         Drawable drawable = Drawable.createFromPath(source);
        try {
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        }catch (NullPointerException e){
            logException(e);
        }
        return drawable;
    }
};
Run Code Online (Sandbox Code Playgroud)

尝试前的"来源"是

http://www.domain.com/images_blog/feature.png

但在捕获中错误是:

无法解码流:

java.io.FileNotFoundException: /http:/www.domain.com/images_blog/feature.png : open failed: ENOENT (No such file or directory)
Run Code Online (Sandbox Code Playgroud)

psk*_*ink 48

最简单的解决方案是:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import org.pskink.soom.R;

import android.app.Activity;
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.os.Bundle;
import android.text.Html;
import android.text.Html.ImageGetter;
import android.text.Spanned;
import android.util.Log;
import android.widget.TextView;

public class TestImageGetter extends Activity implements ImageGetter {
    private final static String TAG = "TestImageGetter";
    private TextView mTv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_image_getter);
        String source = "this is a test of <b>ImageGetter</b> it contains " +
                "two images: <br/>" +
                "<img src=\"http://developer.android.com/assets/images/dac_logo.png\"><br/>and<br/>" +
                "<img src=\"http://developer.android.com/assets/images/icon_search.png\">";

        Spanned spanned = Html.fromHtml(source, this, null);
        mTv = (TextView) findViewById(R.id.text);
        mTv.setText(spanned);
    }

    @Override
    public Drawable getDrawable(String source) {
        LevelListDrawable d = new LevelListDrawable();
        Drawable empty = getResources().getDrawable(R.drawable.ic_launcher);
        d.addLevel(0, 0, empty);
        d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());

        new LoadImage().execute(source, d);

        return d;
    }

    class LoadImage extends AsyncTask<Object, Void, Bitmap> {

        private LevelListDrawable mDrawable;

        @Override
        protected Bitmap doInBackground(Object... params) {
            String source = (String) params[0];
            mDrawable = (LevelListDrawable) params[1];
            Log.d(TAG, "doInBackground " + source);
            try {
                InputStream is = new URL(source).openStream();
                return BitmapFactory.decodeStream(is);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            Log.d(TAG, "onPostExecute drawable " + mDrawable);
            Log.d(TAG, "onPostExecute bitmap " + bitmap);
            if (bitmap != null) {
                BitmapDrawable d = new BitmapDrawable(bitmap);
                mDrawable.addLevel(1, 1, d);
                mDrawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
                mDrawable.setLevel(1);
                // i don't know yet a better way to refresh TextView
                // mTv.invalidate() doesn't work as expected
                CharSequence t = mTv.getText();
                mTv.setText(t);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

图像下载后有一种不太优雅的方式重新布局TextView:

// i don't know yet a better way to refresh TextView
// mTv.invalidate() doesn't work as expected
CharSequence t = mTv.getText();
mTv.setText(t);
Run Code Online (Sandbox Code Playgroud)

如果有人知道更好的解决方案,请告诉我


Mar*_* RS 6

使用GlideCoroutines假设不需要重试的替代解决方案:

import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.text.Html
import android.widget.TextView
import androidx.lifecycle.LifecycleCoroutineScope
import com.bumptech.glide.RequestManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.math.roundToInt

class HtmlImageGetter(
    private val scope: LifecycleCoroutineScope,
    private val res: Resources,
    private val glide: RequestManager,
    private val htmlTextView: TextView
) : Html.ImageGetter {

    override fun getDrawable(url: String): Drawable {
        val holder = BitmapDrawablePlaceHolder(res, null)

        scope.launch(Dispatchers.IO) {
            runCatching {
                val bitmap = glide
                    .asBitmap()
                    .load(url)
                    .submit()
                    .get()

                val drawable = BitmapDrawable(res, bitmap)

                val scale = 1.25 // This makes the image scale in size.
                val width = (drawable.intrinsicWidth * scale).roundToInt()
                val height = (drawable.intrinsicHeight * scale).roundToInt()
                drawable.setBounds(0, 0, width, height)

                holder.setDrawable(drawable)
                holder.setBounds(0, 0, width, height)

                withContext(Dispatchers.Main) { htmlTextView.text = htmlTextView.text }
            }
        }

        return holder
    }

    internal class BitmapDrawablePlaceHolder(res: Resources, bitmap: Bitmap?) : BitmapDrawable(res, bitmap) {
        private var drawable: Drawable? = null

        override fun draw(canvas: Canvas) {
            drawable?.run { draw(canvas) }
        }

        fun setDrawable(drawable: Drawable) {
            this.drawable = drawable
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在 aFragmentActivityHtmlCompat

val imageGetter = HtmlImageGetter(lifecycleScope, resources, glide, htmlTextView)
val styledText = HtmlCompat.fromHtml(htmlString, flags, imageGetter, null)
htmlTextView.text = styledText
Run Code Online (Sandbox Code Playgroud)