Android HTML ImageGetter jako AsyncTask

Dobra, tracę przez to rozum. Mam metodę w moim programie, która parsuje HTML. Chcę dołączyć obrazy w linii i mam wrażenie, że za pomocą Html.fromHtml( string, Html.ImageGetter, Html.TagHandler) pozwoli na to.

Od Html.ImageGetter nie ma implementacji, to do mnie należy napisanie jednej. Ponieważ jednak parsowanie adresów URL do obiektów rysunkowych wymaga dostępu do sieci, nie mogę tego zrobić w głównym wątku, więc musi to być AsyncTask. Tak myślę.

Jednak, gdy przekazujesz ImageGetter jako parametr do Html.fromHtml, używa metody getDrawable, która musi być nadpisana. Więc nie ma sposobu, aby zadzwonić do całego Imagegettera.wykonaj transakcję, która uruchamia metodę doInBackground, więc nie ma sposobu, aby uczynić tę asynchroniczną.

Czy robię to całkowicie źle, czy co gorsza, czy to niemożliwe? Dzięki

Author: Nick, 2011-09-15

5 answers

Zrobiłem coś bardzo podobnego (myślę) do tego, co chcesz zrobić. To, co musiałem wtedy zrobić, to przeanalizować HTML i ustawić go z powrotem do TextView i musiałem również użyć Html.ImageGetter i mieć ten sam problem z pobieraniem obrazu w głównym wątku.

Kroki, które zrobiłem w zasadzie:

  • Utwórz własną podklasę dla Drawable aby ułatwić przerysowywanie, nazwałem ją URLDrawable
  • zwraca URLDrawable w getDrawable metodę Html.ImageGetter
  • Po wywołaniu onPostExecute przerysowuję kontener wyniku Spanned

Teraz kod dla URLDrawable jest następujący


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);
        }
    }
}

Dość proste, po prostu nadpisuję draw, aby wybrać Drawable, który ustawiłem tam po zakończeniu AsyncTask.

Następująca klasa jest implementacją Html.ImageGetter i tą, która pobiera obrazek z AsyncTask i aktualizuje obrazek

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

Na koniec, poniżej znajduje się przykładowy program, aby zademonstrować, jak to działa:

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);
 103
Author: momo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-16 09:35:05

Całkiem nieźle. Jednak typ DefaultHttpClient jest przestarzały. Spróbuj tego w metodzie 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;

    }
 5
Author: Fred Sousa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-01 23:34:12

Trochę się pogubiłem, czy HTML chcesz renderować statycznie i tylko do formatowania, czy jest dynamiczny i pochodzi z sieci? Jeśli chcesz tego ostatniego, czyli renderować HTML i pobierać obrazy, cóż, będzie to trochę bolesne (sugestia - wystarczy użyć widoku sieci Web?).

W każdym razie, musisz najpierw uruchomić AsyncTask, aby odzyskać początkowy HTML. Następnie przekazywałbyś te wyniki do Html.fromHtml() z niestandardową implementacją dla klasy Html.ImageGetter. Wtedy w tym implementacja będziesz musiał uruchomić pojedynczą AsyncTask, aby odzyskać każdy z obrazów (prawdopodobnie chcesz zaimplementować trochę buforowania).

Jednak po przeczytaniu dokumentacji (i chyba widziałem kilka próbek), wydaje mi się, że nie o to chodziło Html.ImageGetter. Myślę, że jest przeznaczony do kodowanego na twardo HTML z odniesieniami do wewnętrznych drawables, ale to tylko moje zdanie.

 1
Author: dmon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-15 04:49:01

Jeśli używasz Picassa, Zmień część kodu @ momo na

/***
         * 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());
        }
 1
Author: Wackaloon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-10 10:35:24

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();
 0
Author: user5881594,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-04 06:25:55