Android HTML ImageGetter 作为 AsyncTask
Posted
技术标签:
【中文标题】Android HTML ImageGetter 作为 AsyncTask【英文标题】:Android HTML ImageGetter as AsyncTask 【发布时间】:2011-11-17 11:30:19 【问题描述】:好的,我正在为这个而失去理智。我的程序中有一个解析 html 的方法。我想包含内联图像,我的印象是使用 Html.fromHtml(string, Html.ImageGetter, Html.TagHandler) 将允许这种情况发生。
由于 Html.ImageGetter 没有实现,由我来编写。但是,由于将URL解析成Drawables需要网络访问,所以我不能在主线程上这样做,所以它必须是一个AsyncTask。我想。
但是,当您将 ImageGetter 作为参数传递给 Html.fromHtml 时,它使用的 getDrawable 方法必须被覆盖。因此无法调用触发 doInBackground 方法的整个 ImageGetter.execute 交易,因此无法真正实现异步。
我是不是完全错了,或者更糟的是,这不可能吗?谢谢
【问题讨论】:
我可能会为此大发雷霆,但为什么不尝试使用自烘焙线程(而不是 asyncTask)来执行此操作。这没有什么可以覆盖的,你可以观察发生的事情。在数据到达后,您需要在主线程中使用处理程序和 Runnable 来调用数据。 @Nick:我很难理解。在什么情况下使用 AsyncTask 是个问题——你认为这其中的哪一部分是行不通的? @MisterSquonk 使用 AsyncTask 是一个问题,因为您必须在对象的实例上调用 execute。但是,要使用 ImageGetter,您将实例作为 Html.fromHtml 函数的参数传递,并且该函数旨在仅调用 ImageGetter 的 getDrawable 方法,该方法将在同一线程上运行,从而导致 NetworkOnMainThreadException 对于与文本重叠的图像,请查看此答案:***.com/a/10208504/1373568(适用于 PRE-ICS,但不适用于 ICS)。 对于使用协程 + Glide 的替代方法,请参阅:***.com/a/58091529/683658 【参考方案1】:我做了一些与你想做的事情非常相似(我认为)的事情。那时我需要做的是解析 HTML 并将其设置回 TextView,我还需要使用 Html.ImageGetter
并且在主线程上获取图像时遇到同样的问题。
我基本做的步骤:
为Drawable创建自己的子类,方便重绘,我称之为URLDrawable 返回Html.ImageGetter
的getDrawable
方法中的URLDrawable
一旦调用onPostExecute
,我就重绘Spanned
结果的容器
现在 URLDrawable 的代码如下
public class URLDrawable extends BitmapDrawable
// the drawable that you need to set, you could set the initial drawing
// with the loading image if you need to
protected Drawable drawable;
@Override
public void draw(Canvas canvas)
// override the draw to facilitate refresh function later
if(drawable != null)
drawable.draw(canvas);
很简单,我只是覆盖了draw
,所以它会在 AsyncTask 完成后选择我在那里设置的 Drawable。
下面的类是Html.ImageGetter
的实现,是从AsyncTask
获取图片并更新图片的类
public class URLImageParser implements ImageGetter
Context c;
View container;
/***
* Construct the URLImageParser which will execute AsyncTask and refresh the container
* @param t
* @param c
*/
public URLImageParser(View t, Context c)
this.c = c;
this.container = t;
public Drawable getDrawable(String source)
URLDrawable urlDrawable = new URLDrawable();
// get the actual source
ImageGetterAsyncTask asyncTask =
new ImageGetterAsyncTask( urlDrawable);
asyncTask.execute(source);
// return reference to URLDrawable where I will change with actual image from
// the src tag
return urlDrawable;
public class ImageGetterAsyncTask extends AsyncTask<String, Void, Drawable>
URLDrawable urlDrawable;
public ImageGetterAsyncTask(URLDrawable d)
this.urlDrawable = d;
@Override
protected Drawable doInBackground(String... params)
String source = params[0];
return fetchDrawable(source);
@Override
protected void onPostExecute(Drawable result)
// set the correct bound according to the result from HTTP call
urlDrawable.setBounds(0, 0, 0 + result.getIntrinsicWidth(), 0
+ result.getIntrinsicHeight());
// change the reference of the current drawable to the result
// from the HTTP call
urlDrawable.drawable = result;
// redraw the image by invalidating the container
URLImageParser.this.container.invalidate();
/***
* Get the Drawable from URL
* @param urlString
* @return
*/
public Drawable fetchDrawable(String urlString)
try
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");
drawable.setBounds(0, 0, 0 + drawable.getIntrinsicWidth(), 0
+ drawable.getIntrinsicHeight());
return drawable;
catch (Exception e)
return null;
private InputStream fetch(String urlString) throws MalformedURLException, IOException
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
最后,下面是演示工作原理的示例程序:
String html = "Hello " +
"<img src='http://www.gravatar.com/avatar/" +
"f9dd8b16d54f483f22c0b7a7e3d840f9?s=32&d=identicon&r=PG'/>" +
" This is a test " +
"<img src='http://www.gravatar.com/avatar/a9317e7f0a78bb10a980cadd9dd035c9?s=32&d=identicon&r=PG'/>";
this.textView = (TextView)this.findViewById(R.id.textview);
URLImageParser p = new URLImageParser(textView, this);
Spanned htmlSpan = Html.fromHtml(html, p, null);
textView.setText(htmlSpan);
【讨论】:
你太棒了,这是一个很好的答案,很好的解释,最重要的是它的效果。谢谢一百万! 这很好用!但是有一个问题,当图像很大并且它们上方有文本行时,图像会覆盖它们上方的文本,而不是文本移动以腾出空间。有什么想法吗? 这很好用,但是,invalidate()
还不够 @maxpower47 建议的那样。如果您事先知道图像的大小,您可以简单地将默认可绘制对象设置为足够大并且无效将起作用,但是,如果您在下载图像之前不知道此信息,并且一些较大的图像与您的文本重叠,您必须强制 textview 重新渲染文本,而不仅仅是 redraw()
或 re-requestLayout()
。一个简单的解决方案是:TextView t = (TextView) URLImageGetterAsync.this.container; t.setText(t.getText());
您可以决定是否需要它比这更强大。
图像重叠错误修复在这里可用:***.com/questions/7870312/…(适用于 pre-ICS 和 ICS)
对我不起作用:(空指针异常:" urlDrawable.setBounds(0, 0, 0 + result.getIntrinsicWidth(), 0"【参考方案2】:
相当不错。但是,不推荐使用 DefaultHttpClient 类型。在 fetch 方法上试试这个:
private InputStream fetch(String urlString) throws MalformedURLException, IOException
URL url = new URL(urlString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = urlConnection.getInputStream();
return stream;
【讨论】:
我遇到了这个问题 ::: The inline style not applied , like style=color:red;"【参考方案3】:我有点困惑,您要呈现的 HTML 是静态的并且仅用于格式化,还是动态的并且来自网络?如果你想要后者,即渲染 HTML 并检索图像,那会有点痛苦(建议 - 只需使用 WebView?)。
无论如何,您首先必须运行 AsyncTask 来检索初始 HTML。然后,您将使用 Html.ImageGetter
类的自定义实现将这些结果传递给 Html.fromHtml()
。然后在那个实现中,你必须启动一个单独的 AsyncTask 来检索每个图像(你可能想要实现一些缓存)。
但是,通过阅读文档(我想我已经看到了一些示例),在我看来这并不是 Html.ImageGetter
的意思。我认为它适用于引用 internal 可绘制对象的硬编码 HTML,但这只是我的看法。
【讨论】:
它来自网络,好吧,我想这是有道理的。我真的不想使用 WebView。我已经写了一个任务,当给定我应用程序不同部分的图像 URL 时,它会返回一个 Drawable,所以也许我可以以某种方式利用它。好痛【参考方案4】:如果您使用毕加索,请将@momo 代码的一部分更改为
/***
* Get the Drawable from URL
* @param urlString
* @return
*/
public Drawable fetchDrawable(String urlString)
try
Drawable drawable = fetch(urlString);
drawable.setBounds(0, 0, 0 + drawable.getIntrinsicWidth(), 0
+ drawable.getIntrinsicHeight());
return drawable;
catch (Exception e)
return null;
private Drawable fetch(String urlString) throws MalformedURLException, IOException
return new BitmapDrawable(c.getResources(), Picasso.with(c).load(urlString).get());
【讨论】:
我遇到了这个问题 ::: The inline style not applied , like style=color:red;"【参考方案5】:AsyncTask 任务 = new AsyncTask ()
@Override
protected String doInBackground(Integer... params)
span = Html.fromHtml(noticeList.get(0)
.getContent(), imgGetter, null);
return null;
@Override
protected void onPostExecute(String result)
super.onPostExecute(result);
text.setMovementMethod(ScrollingMovementMethod
.getInstance());
if(span != null)
text.setText(span);
;
task.execute();
【讨论】:
以上是关于Android HTML ImageGetter 作为 AsyncTask的主要内容,如果未能解决你的问题,请参考以下文章