2010-09-21 55 views
3

我想設置一個TextViewSpannableString這是從下面的方法:使用TextView和Html.ImageGetter異步顯示Android上的圖像?

Html.fromHtml(String source, Html.ImageGetter imageGetter, 
    Html.TagHandler tagHandler) 

但這裏的ImageGetter需要重寫下面的方法:

public abstract Drawable getDrawable(String source) 

因爲我需要從繪製互聯網,我必須做到異步,看起來不是。

如何使它工作? 謝謝。

回答

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()來重新繪製下載的圖像時,它失敗了。我必須在AsyncTask中再次執行setText()

有誰知道爲什麼?

+0

你可以分享你的代碼..你的解決方案聽起來真的很有趣... – 2012-12-15 15:43:26

+0

嗨,我只是設置了跨文本內容的文本。它會再次觸發ImageGetter。 – shiami 2012-12-17 03:47:49

+0

我在談論ImageDownloadAsyncTask(textView,htmlString,source)爲什麼它需要htmlString asparameter? – 2012-12-17 07:34:15

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()); 
    } 
} 
+0

嗨,我的想法似乎與你的想法一樣。完成下載圖像後,您必須再次設置文本。 – shiami 2013-08-05 03:51:19

+0

感謝此代碼片段。如果要覆蓋多個屏幕大小,可以使用DisplayMetrics類有效設置邊界。 – Khobaib 2014-01-04 05:46:07

12

這些傢伙的表現非常出色,這是使用Square的畢加索庫我解決方案:

//... 
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美分......和平!

+0

這太棒了! – aidan 2015-07-16 12:11:48

+0

是的!複製,粘貼,享受:D – Labe 2016-04-05 15:03:49

+0

請問爲什麼在這裏使用'LevelListDrawable' @cass_?什麼是所有'addLevel'和'setLevel'? – ericn 2016-09-18 07:38:56

相關問題