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
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
wgetDrawable
metodęHtml.ImageGetter
- Po wywołaniu
onPostExecute
przerysowuję kontener wynikuSpanned
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);
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;
}
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.
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());
}
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();
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