2015-06-08 4 views
4

В моем случае я использовал WebView для визуализации и отображения сведений о новостях, и я хочу обрабатывать загрузку и кеширование изображений самостоятельно, а не WebView. поэтому я использовал Пикассо для моих изображений Lib, как показано ниже:Как использовать WebView с Picasso?

@TargetApi(Build.VERSION_CODES.HONEYCOMB) 
@Override 
public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 
    if (!Utils.hasHoneycomb()||TextUtils.isEmpty(url)||url.startsWith("file://")) { 
     return super.shouldInterceptRequest(view, url); 
    } 
    if (!url.startsWith("http") || !url.endsWith(".jpg") || !url.endsWith(".jpeg") || !url.endsWith(".png")) { 
     return super.shouldInterceptRequest(view, url); 
    } 

    WebResourceResponse response = null; 
    try { 
     final PipedOutputStream out = new PipedOutputStream(); 
     PipedInputStream in = new PipedInputStream(out); 

     Picasso.with(Application.getInstance()).load(url).into(new Target() { 
      @Override 
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 
       if (bitmap != null) { 
        try { 
         out.write(StreamTool.bmp2ByteArray100(bitmap, false)); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } finally { 
         try { 
          out.close(); 
         } catch (IOException e) { 
          e.printStackTrace(); 
         } 
        } 
       } 
      } 

      @Override 
      public void onBitmapFailed(Drawable errorDrawable) { 

      } 

      @Override 
      public void onPrepareLoad(Drawable placeHolderDrawable) { 

      } 
     }); 
     response = new WebResourceResponse("image/*", "UTF-8", in); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return response; 
} 

, но он не работает, и я знаю shouldInterceptRequest работы в не-UI потоке, Picassso

throw new IllegalStateException("Method call should happen from the main thread."); 

так у меня есть два вопросы:

  1. Каков общий способ обработки изображений и кеширования самостоятельно, а не WebView?
  2. Как использовать Picasso с основной резьбой?

ОБНОВЛЕНО (добавление стека исключений):

06-08 18:17:05.540 5137-6951/com.news.daily I/dalvikvm﹕ java.lang.IllegalStateException: Method call should happen from the main thread. 
 
06-08 18:17:05.540 5137-6951/com.news.daily I/dalvikvm﹕ at com.squareup.picasso.Utils.checkMain(Utils.java:136) 
 
06-08 18:17:05.540 5137-6951/com.news.daily I/dalvikvm﹕ at com.squareup.picasso.RequestCreator.into(RequestCreator.java:496) 
 
06-08 18:17:05.540 5137-6951/com.news.daily I/dalvikvm﹕ at com.news.daily.widget.webview.WebViewClientDaily.shouldInterceptRequest(WebViewClientDaily.java:123) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.CallbackProxy.shouldInterceptRequest(CallbackProxy.java:1534) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.BrowserFrame.shouldInterceptRequest(BrowserFrame.java:972) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.WebSettingsClassic.nativeSync(Native Method) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.WebSettingsClassic.access$100(WebSettingsClassic.java:50) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.WebSettingsClassic$EventHandler$1.handleMessage(WebSettingsClassic.java:291) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.os.Handler.dispatchMessage(Handler.java:99) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.os.Looper.loop(Looper.java:137) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:1092) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ at java.lang.Thread.run(Thread.java:841) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ DALVIK THREADS: 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ (mutexes: tll=0 tsl=0 tscl=0 ghl=0) 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ "main" prio=5 tid=1 NATIVE 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ | group="main" sCount=0 dsCount=0 obj=0x419dc710 self=0x419c60f0 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ | sysTid=5137 nice=0 sched=0/0 cgrp=apps handle=1074810876 
 
06-08 18:17:05.550 5137-6951/com.news.daily I/dalvikvm﹕ | state=S schedstat=(3242900256 1453466203 12922) utm=238 stm=86 core=3 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #00 pc 0001c6ec /system/lib/libc.so (epoll_wait+12) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #01 pc 000153f1 /system/lib/libutils.so (android::Looper::pollInner(int)+92) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #02 pc 00015615 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+92) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #03 pc 000729ed /system/lib/libandroid_runtime.so (android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #04 pc 00020c0c /system/lib/libdvm.so (dvmPlatformInvoke+112) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #05 pc 0005178b /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ #06 pc 00000214 /dev/ashmem/dalvik-jit-code-cache (deleted) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at android.os.MessageQueue.nativePollOnce(Native Method) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at android.os.MessageQueue.next(MessageQueue.java:132) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at android.os.Looper.loop(Looper.java:124) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at android.app.ActivityThread.main(ActivityThread.java:5450) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at java.lang.reflect.Method.invokeNative(Native Method) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at java.lang.reflect.Method.invoke(Method.java:525) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ at dalvik.system.NativeStart.main(Native Method) 
 
06-08 18:17:05.560 5137-6951/com.news.daily I/dalvikvm﹕ [ 06-08 18:17:05.560 5137: 6951 I/dalvikvm ] 
 
"AsyncTask #10" prio=5 tid=41 WAIT

+0

Вместо стека сообщений IllegalStateException с источником исключения (строка и т. Д.) – dasar

+0

@dasar я добавил стек исключений, thx. – Xiaozou

+0

Почему вы не просите Пикассо загружать изображения в нити ui? Он сделает запросы в фоновом режиме для вас ... Вы занимаетесь? –

ответ

2

ГЭТ() метод позволяет использовать фоновый поток, чтобы получить изображение, которое вы хотите напрямую , Нет необходимости в Target.

В настоящее время при вызове в() с этим обходным путем всегда существовал случай случайный поток был использован для извлечения вашего изображения на цель.

Это была ошибка Пикассо, чтобы позволить внешним вызывающим абонентам ссылаться на в() кроме основной темы. Эти методы относятся к просмотру для утилизации и отмены без синхронизации, поэтому в Picasso 2.3 мы добавили проверки. From official discussion

Таким образом, вы можете использовать get() метод вместо into(), который должен быть вызван только из UI потока. Вы можете использовать OkHttp в качестве http-клиента для Picasso, поскольку он имеет встроенный кеш. Также вы можете переопределить правила кэширования, перехватывая запросы в OkHttp. Эти две библиотеки хорошо сочетаются.

+0

Поскольку метод mustInterceptRequest работает в потоке, отличном от UI, поэтому, если Picasso поддерживает внешние вызывающие элементы от основного потока, мои проблемы будут решены. – Xiaozou

+0

Вам просто нужно использовать get() api вместо() – dasar

+0

спасибо, я должен использовать get() api – Xiaozou

0

Вот решение, которое я закончил с после объединения @ примера Xiaozou и предложения от @dasar:

webView.setWebViewClient(new WebViewClient() { 
    @SuppressWarnings("deprecation") 
    @Override 
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) { 
     final String mime = URLConnection.guessContentTypeFromName(url); 
     if (mime == null || !mime.startsWith("image")) { 
      return super.shouldInterceptRequest(view, url); 
     } 
     try { 
      final Bitmap image = Picasso.with(context).load(url).get(); 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
      if (mime.endsWith("jpeg")) { 
       image.compress(Bitmap.CompressFormat.JPEG, 100, out); 
      } else if (mime.endsWith("png")) { 
       image.compress(Bitmap.CompressFormat.PNG, 100, out); 
      } else { 
       return super.shouldInterceptRequest(view, url); 
      } 
      InputStream in = new ByteArrayInputStream(out.toByteArray()); 
      return new WebResourceResponse(mime, "UTF-8", in); 
     } catch (IOException e) { 
      Log.e(TAG, "Unable to load image", e); 
      return super.shouldInterceptRequest(view, url); 
     } 
    } 
}); 

Я не использовал PipedOutputStream, потому что запрос будет просто завершает внутри Bitmap.compress вызовов и не бросайте ошибки.

Смежные вопросы