如何在Picasso中使用WebView?

时间:2015-06-08 09:59:39

标签: android webview picasso

在我的情况下,我使用WebView来呈现和显示新闻细节,我想通过自己而不是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?
  3. 更新(添加异常堆栈):

    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

2 个答案:

答案 0 :(得分:2)

  

get()方法允许您使用后台线程来检索   你想直接的形象。不需要Target。

     

目前通过使用此解决方法调用into()总是有一个   很有可能使用后台线程来获取目标上的图像。

     

毕加索允许外部呼叫者调用是错误的   into()除主线程外。这些方法涉及观点   因此在Picasso 2.3中没有同步地回收和取消   我们添加了支票。   From official discussion

因此,您可以使用get()方法而不是into(),只能从UI线程调用它。您可以使用OkHttp作为Picasso的http客户端,因为它内置了缓存。您还可以通过拦截OkHttp中的查询来覆盖缓存规则。这两个图书馆一起玩得很好。

答案 1 :(得分:1)

这是我在结合@ 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次调用中终止而不会抛出任何错误。