我想设置一个TextView
SpannableString
来自下面的方法:
Html.fromHtml(String source, Html.ImageGetter imageGetter,
Html.TagHandler tagHandler)
但是ImageGetter
这里需要覆盖以下方法:
public abstract Drawable getDrawable(String source)
因为我需要从互联网上获取可绘制的内容,所以我必须异步进行,但似乎不是。
如何让它发挥作用? 感谢。
答案 0 :(得分:14)
这些家伙做得很好,这是我使用Square的Picasso图书馆的解决方案:
//...
final TextView textView = (TextView) findViewById(R.id.description);
Spanned spanned = Html.fromHtml(getIntent().getStringExtra(EXTRA_DESCRIPTION),
new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
LevelListDrawable d = new LevelListDrawable();
Drawable empty = getResources().getDrawable(R.drawable.abc_btn_check_material);;
d.addLevel(0, 0, empty);
d.setBounds(0, 0, empty.getIntrinsicWidth(), empty.getIntrinsicHeight());
new ImageGetterAsyncTask(DetailActivity.this, source, d).execute(textView);
return d;
}
}, null);
textView.setText(spanned);
//...
class ImageGetterAsyncTask extends AsyncTask<TextView, Void, Bitmap> {
private LevelListDrawable levelListDrawable;
private Context context;
private String source;
private TextView t;
public ImageGetterAsyncTask(Context context, String source, LevelListDrawable levelListDrawable) {
this.context = context;
this.source = source;
this.levelListDrawable = levelListDrawable;
}
@Override
protected Bitmap doInBackground(TextView... params) {
t = params[0];
try {
Log.d(LOG_CAT, "Downloading the image from: " + source);
return Picasso.with(context).load(source).get();
} catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(final Bitmap bitmap) {
try {
Drawable d = new BitmapDrawable(context.getResources(), bitmap);
Point size = new Point();
((Activity) context).getWindowManager().getDefaultDisplay().getSize(size);
// Lets calculate the ratio according to the screen width in px
int multiplier = size.x / bitmap.getWidth();
Log.d(LOG_CAT, "multiplier: " + multiplier);
levelListDrawable.addLevel(1, 1, d);
// Set bounds width and height according to the bitmap resized size
levelListDrawable.setBounds(0, 0, bitmap.getWidth() * multiplier, bitmap.getHeight() * multiplier);
levelListDrawable.setLevel(1);
t.setText(t.getText()); // invalidate() doesn't work correctly...
} catch (Exception e) { /* Like a null bitmap, etc. */ }
}
}
我的2美分......和平!
答案 1 :(得分:4)
现在我正在使用AsyncTask下载ImageGetter
中的图像:
Spanned spannedContent = Html.fromHtml(htmlString, new ImageGetter() {
@Override
public Drawable getDrawable(String source) {
new ImageDownloadAsyncTask().execute(textView, htmlString, source);
return null;
}
}, null);
并在下载图片后再次将文字设置为TextView
。
现在它有效。但是当我尝试TextView.postInvalidate()
重绘下载的图像时失败了。我必须在setText()
中再次AsyncTask
。
有谁知道为什么?
答案 2 :(得分:4)
这是我的代码,它抓取html字符串中的所有图像(它从原始文件中简化,所以我希望它有效):
private HashMap<String, Drawable> mImageCache = new HashMap<String, Drawable>();
private String mDescription = "...your html here...";
private void updateImages(final boolean downloadImages) {
if (mDescription == null) return;
Spanned spanned = Html.fromHtml(mDescription,
new Html.ImageGetter() {
@Override
public Drawable getDrawable(final String source) {
Drawable drawable = mImageCache.get(source);
if (drawable != null) {
return drawable;
} else if (downloadImages) {
new ImageDownloader(new ImageDownloader.ImageDownloadListener() {
@Override
public void onImageDownloadComplete(byte[] bitmapData) {
Drawable drawable = new BitmapDrawable(getResources(),
BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length));
try {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
} catch (Exception ex) {}
mImageCache.put(source, drawable);
updateImages(false);
}
@Override
public void onImageDownloadFailed(Exception ex) {}
}).execute(source);
}
return null;
}
}, null);
tvDescription.setText(spanned);
}
所以基本上这里发生的是ImageGetter将对html描述中的每个图像发出请求。如果该图像不在mImageCache数组中且downloadImages为true,则我们运行异步任务来下载该图像。一旦完成,我们将drawable添加到hashmap中,然后再次调用此方法(但将downloadImages视为false,这样我们就不会冒无限循环的风险),其中图像将能够被抓取第二次尝试。
然后,你需要我使用的ImageDownloader类:
public class ImageDownloader extends AsyncTask {
public interface ImageDownloadListener {
public void onImageDownloadComplete(byte[] bitmapData);
public void onImageDownloadFailed(Exception ex);
}
private ImageDownloadListener mListener = null;
public ImageDownloader(ImageDownloadListener listener) {
mListener = listener;
}
protected Object doInBackground(Object... urls) {
String url = (String)urls[0];
ByteArrayOutputStream baos = null;
InputStream mIn = null;
try {
mIn = new java.net.URL(url).openStream();
int bytesRead;
byte[] buffer = new byte[64];
baos = new ByteArrayOutputStream();
while ((bytesRead = mIn.read(buffer)) > 0) {
if (isCancelled()) return null;
baos.write(buffer, 0, bytesRead);
}
return new AsyncTaskResult<byte[]>(baos.toByteArray());
} catch (Exception ex) {
return new AsyncTaskResult<byte[]>(ex);
}
finally {
Quick.close(mIn);
Quick.close(baos);
}
}
protected void onPostExecute(Object objResult) {
AsyncTaskResult<byte[]> result = (AsyncTaskResult<byte[]>)objResult;
if (isCancelled() || result == null) return;
if (result.getError() != null) {
mListener.onImageDownloadFailed(result.getError());
}
else if (mListener != null)
mListener.onImageDownloadComplete(result.getResult());
}
}