RichText icon indicating copy to clipboard operation
RichText copied to clipboard

synchronized导致ANR

Open 1wayticket opened this issue 5 years ago • 4 comments

richtext:v3.0.7 在anr日志里找到两处锁导致的anr 1 ANR Broadcast of Intent { act=android.intent.action.TIME_TICK flg=0x50200014 (has extras) } com.mszmapp.detective.utils.richtext.f.g.a(DefaultImageGetter.java:56) 经检查发现时DefaultImageGetter-->checkTarget(TextView textView) 有一个主线程的synchronized 2 ANR Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 30. Wait queue head age: 5691.0ms.) com.mszmapp.detective.utils.richtext.f.j$d.a(ImageDownloaderManager.java:160) 也是ImageDownloaderManager-->removeCallback(CallbackImageLoader callbackImageLoader) 给callback加锁导致anr 项目好像一直不更新了,有点可惜。

1wayticket avatar Dec 18 '19 06:12 1wayticket

richtext:v3.0.7 在anr日志里找到两处锁导致的anr 1 ANR Broadcast of Intent { act=android.intent.action.TIME_TICK flg=0x50200014 (has extras) } com.mszmapp.detective.utils.richtext.f.g.a(DefaultImageGetter.java:56) 经检查发现时DefaultImageGetter-->checkTarget(TextView textView) 有一个主线程的synchronized 2 ANR Input dispatching timed out (Waiting to send non-key event because the touched window has not finished processing certain input events that were delivered to it over 500.0ms ago. Wait queue length: 30. Wait queue head age: 5691.0ms.) com.mszmapp.detective.utils.richtext.f.j$d.a(ImageDownloaderManager.java:160) 也是ImageDownloaderManager-->removeCallback(CallbackImageLoader callbackImageLoader) 给callback加锁导致anr 项目好像一直不更新了,有点可惜。

我也遇到这种问题了,大哥有找到解决方法吗

davidgerka avatar Jan 22 '20 03:01 davidgerka

我也遇到了这个问题

zzzsssbo avatar Mar 31 '20 08:03 zzzsssbo

package com.mszmapp.detective.utils.richtext.ig;

import com.mszmapp.detective.utils.richtext.ImageHolder;
import com.mszmapp.detective.utils.richtext.cache.BitmapPool;
import com.mszmapp.detective.utils.richtext.callback.BitmapStream;
import com.mszmapp.detective.utils.richtext.exceptions.ImageDownloadTaskAddFailureException;
import com.mszmapp.detective.utils.richtext.exceptions.ImageLoadCancelledException;
import com.mszmapp.detective.utils.richtext.ext.Debug;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by zhou on 2017/10/9.
 * 图片下载管理器
 */

class ImageDownloaderManager {


    private final HashMap<String, Task> tasks;


    private ImageDownloaderManager() {
        tasks = new HashMap<>();
    }


    static ImageDownloaderManager getImageDownloaderManager() {
        return ImageDownloaderManagerHolder.IMAGE_DOWNLOADER_MANAGER;
    }


    Cancelable addTask(ImageHolder holder, ImageDownloader imageDownloader, CallbackImageLoader callbackImageLoader) {
        String key = holder.getKey();
        synchronized (tasks) {
            Task task = tasks.get(key);
            if (task == null) {
                task = new Task(holder.getSource(), key, imageDownloader, IMAGE_READY_CALLBACK);
                tasks.put(key, task);
            }
            return task.exec(getExecutorService(), callbackImageLoader);
        }
    }

    private final ImageDownloadFinishCallback IMAGE_READY_CALLBACK = new ImageDownloadFinishCallback() {
        @Override
        public void imageDownloadFinish(String key) {
            synchronized (tasks) {
                tasks.remove(key);
            }
        }
    };

    public interface ImageDownloadFinishCallback {

        void imageDownloadFinish(String key);

    }


    private static class TaskCancelable implements Cancelable {

        private WeakReference<Task> taskWeakReference;
        private WeakReference<CallbackImageLoader> callbackImageLoaderWeakReference;

        TaskCancelable(Task task, CallbackImageLoader callbackImageLoader) {
            this.taskWeakReference = new WeakReference<>(task);
            this.callbackImageLoaderWeakReference = new WeakReference<>(callbackImageLoader);
        }

        @Override
        public void cancel() {
            Task task = taskWeakReference.get();
            if (task != null) {
                CallbackImageLoader callbackImageLoader = callbackImageLoaderWeakReference.get();
                if (callbackImageLoader != null) {
                    task.removeCallback(callbackImageLoader);
                    callbackImageLoader.onFailure(new ImageLoadCancelledException());
                }
            }
        }
    }

    private static class Task implements Runnable {

        private static final int STATE_INIT = 0;
        private static final int STATE_WORK = 1;
        private static final int STATE_CALLBACK = 2;
        private static final int STATE_FINISHED = 3;

        private final String key;
        private final String imageUrl;
        private final ImageDownloader imageDownloader;

        private volatile int state;

        private final Object stateLock = new Object();

        private final CopyOnWriteArrayList<CallbackImageLoader> callbackList;
        private final ImageDownloadFinishCallback imageDownloadFinishCallback;

        Task(String imageUrl, String key, ImageDownloader imageDownloader, ImageDownloadFinishCallback imageDownloadFinishCallback) {
            this.imageUrl = imageUrl;
            this.imageDownloader = imageDownloader;
            this.imageDownloadFinishCallback = imageDownloadFinishCallback;
            this.state = STATE_INIT;

            this.callbackList = new CopyOnWriteArrayList<>();

            this.key = key;
        }

        @Override
        public void run() {

            synchronized (stateLock) {
                state = STATE_WORK;
            }

            Exception exception = null;

            try {
                BitmapStream bitmapStream = imageDownloader.download(imageUrl);
                BitmapPool.getPool().writeBitmapToTemp(key, bitmapStream.getInputStream());
                bitmapStream.close();
            } catch (Exception e) {
                exception = e;
            }

            synchronized (stateLock) {

                imageDownloadFinishCallback.imageDownloadFinish(key);

                if (state != STATE_WORK) {
                    return;
                }

                state = STATE_CALLBACK;

//                synchronized (callbackList) {

                for (CallbackImageLoader imageLoader : callbackList) {
                    try {
                        imageLoader.onImageDownloadFinish(key, exception);
                    } catch (Throwable e) {
                        Debug.e(e);
                    }
                }
//                }
                state = STATE_FINISHED;
            }
        }

        private void removeCallback(CallbackImageLoader callbackImageLoader) {
//            synchronized (callbackList) {
            callbackList.remove(callbackImageLoader);
//            }
        }

        private Cancelable exec(ExecutorService executorService, CallbackImageLoader callbackImageLoader) {
            Cancelable cancelable = null;
            synchronized (stateLock) {
                if (state == STATE_WORK) {
//                    synchronized (callbackList) {
                    callbackList.add(callbackImageLoader);
                    cancelable = new TaskCancelable(this, callbackImageLoader);
//                    }
                }
                if (state == STATE_INIT) {
                    state = STATE_WORK;
                    executorService.submit(this);

//                    synchronized (callbackList) {
                    callbackList.add(callbackImageLoader);
                    cancelable = new TaskCancelable(this, callbackImageLoader);
//                    }l
                }
            }
            if (cancelable == null) {
                callbackImageLoader.onFailure(new ImageDownloadTaskAddFailureException());
            }
            return cancelable;
        }

    }


    private static ExecutorService getExecutorService() {
        return ExecutorServiceHolder.EXECUTOR_SERVICE;
    }


    private static class ExecutorServiceHolder {

        private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();

    }

    private static class ImageDownloaderManagerHolder {

        private static final ImageDownloaderManager IMAGE_DOWNLOADER_MANAGER = new ImageDownloaderManager();

    }

}

改成这样试试,作者不维护了,还是找个更靠谱的富文本解析器吧.

1wayticket avatar Mar 31 '20 09:03 1wayticket

谢谢,现在好点的富文本不好找啊

zzzsssbo avatar Apr 01 '20 10:04 zzzsssbo