近日,又在简网的工程上面发现了一个使用上的错误而导致的ANR:

private void asyncLoadPageImage(final List<String> imageUrls) {
            Log.d(TAG, "asyncLoadPageImage");
            if (zhiyueApplication.isArticleNeedImage() && imageUrls != null && imageUrls.size() > 0) {
                Log.d(TAG, "asyncLoadPageImage size = " + imageUrls.size());
                new Handler().postDelayed(new Runnable() {
                    public void run() {
                        imageLoader.load(imageUrls, new ArticleImageLoader.Callback() {
                            public void finished(boolean success, String url, File localFile) {
                                if (success && webView != null) {
                                    webView.getSettings().setLoadsImagesAutomatically(true);
                                    resetImageUrls.remove(url);
                                    String localImageUrl = "file://" + localFile.getAbsolutePath();
                                    String md5 = MD5String.getMD5(localImageUrl);
                                    webView.loadUrl(HtmlBuilder.buildchangeImageSrcScript(md5, localImageUrl));
                                }
                            }
                        });
                    }
                }, 100);

            } else {
                Log.d(TAG, "asyncLoadPageImage = " + imageUrls);
            }
        }

上述这段代码编译运行都不会出现问题,但还是有一个毛病,显然开发者误以为

new Handler().postDelayed(newRunnable()

可以开启一个子线程去做一些耗时处理,于是连方法名都是asyncLoad。但实际上这样使用还是在主线程里去实现。我们接着看下去,注意这里的imageLoader不是那个著名的第三方框架ImageLoader,而是开发者自己封装的。我们来看看load()方法中做了哪些事情:

public void load(List<String> imageUrls, Callback callback) {
        if (imageUrls != null && imageUrls.size() > 0) {
            cancelAll();
            innerCallback = new InnerCallback(imageUrls, callback);

            for (String imageUrl : imageUrls) {
                imageFetcher.loadImageToLocal(imageUrl, innerCallback);
            }
        }
    }

貌似没有问题,接着看下循环里的代码:

public void loadImageToLocal(String url, ImageWorker.Download2LocalCallback callback) {
        zhiyueImageFetcher.load2Local(url, callback);
    }

这个封装简单易懂。继续:

    public void load2Local(String url, Download2LocalCallback callback) {
        File localFile = getLocalFileObject(url);
        if (localFile.exists()) {
            if (localFile.length() > 0) {
                asyncCallback(callback, true, url, localFile);
                return;
            }
            else {
                localFile.delete();
            }
        }
        else {
            Log.d(TAG, "image not exist " + localFile.getAbsolutePath() + ", url = " + url);
        }

        Download2LocalTask download2LocalTask = new Download2LocalTask(url, callback);
        multiUrlQueryController.add(url, download2LocalTask);
        download2LocalTask.execute();
    }

来到本次事故的事发地。注意,直到上面这个方法中,我们还在主线程。看看上面方法,我们在主线程中创建了文件,并判断文件是否存在。嗯,这是一个耗时操作,如果这里出现了ANR,接下来的代码执行的怎么样,都没必要讲了。可以看出开发者意识到文件的处理是个耗时的过程,只不过是他用错了而已。

所以这里出现ANR的原因是错误使用new Handler().postDelayed(newRunnable()

results matching ""

    No results matching ""