Android HTML ImageGetter как AsyncTask

Хорошо, я схожу с ума по этому. У меня есть метод в моей программе, который анализирует HTML. Я хочу включить встроенные изображения, и у меня сложилось впечатление, что использование Html.fromHtml(string, Html.ImageGetter, Html.TagHandler) позволит этому произойти.

Поскольку Html.ImageGetter не имеет реализации, я должен написать ее. Однако, поскольку для разбора URL-адресов в Drawables требуется доступ к сети, я не могу сделать это в главном потоке, поэтому это должен быть AsyncTask. Я думаю.

Однако, когда вы передаете ImageGetter в качестве параметра Html.fromHtml, он использует метод getDrawable, который должен быть переопределен. Таким образом, нет способа вызвать всю сделку ImageGetter.execute, которая запускает метод doInBackground, и, таким образом, не существует способа сделать это асинхронным.

Я иду по этому поводу совершенно неправильно, или хуже, это невозможно? Спасибо

5 ответов

Решение

Я сделал что-то очень похожее (я думаю), что вы хотите сделать. Тогда мне нужно было разобрать HTML-код и установить его обратно в TextView, и мне нужно было использовать Html.ImageGetter а также с той же проблемой при получении изображения в главном потоке.

Шаги, которые я сделал в основном:

  • Создайте свой собственный подкласс для Drawable для облегчения перерисовки, я назвал его URLDrawable
  • Вернуть URLDrawable в getDrawable метод Html.ImageGetter
  • однажды 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 поэтому он выберет Drawable, который я установил там после завершения AsyncTask.

Следующий класс является реализацией 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);

Довольно мило Однако тип DefaultHttpClient устарел. Попробуйте этот метод извлечения:

private InputStream fetch(String urlString) throws MalformedURLException, IOException {

        URL url = new URL(urlString);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream stream = urlConnection.getInputStream();

        return stream;

    }

Я немного запутался, является ли HTML, который вы хотите визуализировать, статичным и просто для форматирования, или он динамический и поступает из Интернета? Если вы хотите, чтобы последний, то есть визуализировал HTML и извлекал изображения, ну, это будет немного больно (совет - просто используйте WebView?).

В любом случае, вам сначала нужно запустить AsyncTask для получения исходного HTML. Затем вы передадите эти результаты в Html.fromHtml() с пользовательской реализацией для Html.ImageGetter учебный класс. Затем в этой реализации вам нужно будет запустить отдельную AsyncTask для извлечения каждого из изображений (вы, вероятно, захотите реализовать некоторое кэширование).

Однако, прочитав документацию (и я думаю, что я видел несколько примеров), мне показалось, что это не то, что они имели в виду. Html.ImageGetter за. Я думаю, что это предназначено для жестко закодированного HTML со ссылками на внутренние элементы рисования, но это только мое мнение.

Если вы используете Picasso, измените часть кода @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());
        }

AsyncTask task = 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();
Другие вопросы по тегам