输入调度超时引起的ANR-尝试获取我的公共IP地址

12
我收到以下完整的错误信息:输入分派超时(等待发送非键事件,因为触摸窗口尚未完成处理某些输入事件,这些事件在500.0ms之前传递给它。等待队列长度:2。等待队列头龄:9379.7ms。)
请见下面的代码+跟踪。看起来锁定发生在 GetIP_WAN.java:32 这一行:
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));

每当我检测到网络变化wifi-3g/4g无互联网时,我都会调用此函数,在其他几个地方也会这样做。它在每个场合都会发生,但显然在网络变化检测方面更加频繁。

我通过以下方式验证公共IP是否已更改:

ipwan = giw.getWanIpAddress();

并在getWanIpAddress函数中:

ipwan = new GetIP_WAN().execute().get();

ipwan是指向公共IP的字符串。

我无法重现此ANR。

我的应用程序使用多个异步任务,可能会进行几秒钟的密集异步任务。如果我使用大负载进行测试,并关闭WiFi,我没有问题。

非常感谢您提供的输入!

public class GetIP_WAN extends AsyncTask<Void, Integer, String> {

    @Override
    protected  String doInBackground(Void... params) {
        URL url;

        String ipwan = null;
        try {
            // get URL content
            url = new URL("http://ipv4bot.whatismyipaddress.com/");
            URLConnection conn = url.openConnection();

            conn.setConnectTimeout(3000);

            // open the stream and put it into BufferedReader
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));

            String inputLine;
            ipwan = br.readLine();

            br.close();
        } catch (java.net.SocketTimeoutException e) {
            return ("timeout");
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return ("malformed");
        } catch (IOException e) {
            e.printStackTrace();
            return ("exception");
        }
        return (ipwan);
    }

}

这里是追踪信息(我的代码中锁定的位置用 >>> 标识):

"main" tid=1 Waiting 
"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 obj=0x7331b000 self=0xb81bb2c0
  | sysTid=23053 nice=-4 cgrp=default sched=0/0 handle=0xb6f5cbec
  | state=S schedstat=( 26983505120 16031385654 42843 ) utm=2225 stm=473 core=0 HZ=100
  | stack=0xbe5d4000-0xbe5d6000 stackSize=8MB
  | held mutexes=
  at java.lang.Object.wait! (Native method)
- waiting on <0x0448108a> (a java.lang.Object)
  at java.lang.Thread.parkFor (Thread.java:1220)
- locked <0x0448108a> (a java.lang.Object)
  at sun.misc.Unsafe.park (Unsafe.java:299)
  at java.util.concurrent.locks.LockSupport.park (LockSupport.java:157)
  at java.util.concurrent.FutureTask.awaitDone (FutureTask.java:400)
  at java.util.concurrent.FutureTask.get (FutureTask.java:162)
  at android.os.AsyncTask.get (AsyncTask.java:487)
  >>>   at com.bernard_zelmans.checksecurity.Connectivity.GetInfoWan.getWanIpAddress (GetInfoWan.java:168)
  >>>   at com.bernard_zelmans.checksecurity.Connectivity.ConnectivityFragment$2.onClick (ConnectivityFragment.java:155)
  at android.view.View.performClick (View.java:4781)
  at android.view.View$PerformClick.run (View.java:19874)
  at android.os.Handler.handleCallback (Handler.java:739)
  at android.os.Handler.dispatchMessage (Handler.java:95)
  at android.os.Looper.loop (Looper.java:135)
  at android.app.ActivityThread.main (ActivityThread.java:5254)
  at java.lang.reflect.Method.invoke! (Native method)
  at java.lang.reflect.Method.invoke (Method.java:372)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:902)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:697)
"AsyncTask #5" tid=21 Native Performing network I/O
"AsyncTask #5" prio=5 tid=21 Native
  | group="main" sCount=1 dsCount=0 obj=0x1372b0a0 self=0xb8537190
  | sysTid=23175 nice=10 cgrp=bg_non_interactive sched=0/0 handle=0xb8536ee0
  | state=S schedstat=( 9854319 53209536 49 ) utm=0 stm=0 core=0 HZ=100
  | stack=0xa413d000-0xa413f000 stackSize=1036KB
  | held mutexes=
  native: pc 000000000003a180  /system/lib/libc.so (recvfrom+16)
  native: pc 0000000000020165  /system/lib/libjavacore.so (???)
  native: pc 00000000002d557d  /data/dalvik-cache/arm/system@framework@boot.oat (Java_libcore_io_Posix_recvfromBytes__Ljava_io_FileDescriptor_2Ljava_lang_Object_2IIILjava_net_InetSocketAddress_2+176)
  at libcore.io.Posix.recvfromBytes (Native method)
  at libcore.io.Posix.recvfrom (Posix.java:185)
  at libcore.io.BlockGuardOs.recvfrom (BlockGuardOs.java:250)
  at libcore.io.IoBridge.recvfrom (IoBridge.java:553)
  at java.net.PlainSocketImpl.read (PlainSocketImpl.java:485)
  at java.net.PlainSocketImpl.access$000 (PlainSocketImpl.java:37)
  at java.net.PlainSocketImpl$PlainSocketInputStream.read (PlainSocketImpl.java:237)
  at com.android.okio.Okio$2.read (Okio.java:113)
  at com.android.okio.RealBufferedSource.indexOf (RealBufferedSource.java:147)
  at com.android.okio.RealBufferedSource.readUtf8LineStrict (RealBufferedSource.java:94)
  at com.android.okhttp.internal.http.HttpConnection.readResponse (HttpConnection.java:179)
  at com.android.okhttp.internal.http.HttpTransport.readResponseHeaders (HttpTransport.java:101)
  at com.android.okhttp.internal.http.HttpEngine.readResponse (HttpEngine.java:628)
  at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute (HttpURLConnectionImpl.java:388)
  at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse (HttpURLConnectionImpl.java:332)
  at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream (HttpURLConnectionImpl.java:199)
  >>>  at com.bernard_zelmans.checksecurity.Connectivity.GetIP_WAN.doInBackground (GetIP_WAN.java:32)
  >>>  at com.bernard_zelmans.checksecurity.Connectivity.GetIP_WAN.doInBackground (GetIP_WAN.java:16)
  at android.os.AsyncTask$2.call (AsyncTask.java:292)
  at java.util.concurrent.FutureTask.run (FutureTask.java:237)
  at android.os.AsyncTask$SerialExecutor$1.run (AsyncTask.java:231)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1112)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:587)
  at java.lang.Thread.run (Thread.java:818)
"WifiManager" tid=22 Native 
"WifiManager" prio=5 tid=22 Native
  | group="main" sCount=1 dsCount=0 obj=0x137192e0 self=0xb85369a0
  | sysTid=23176 nice=0 cgrp=default sched=0/0 handle=0xb84af978
  | state=S schedstat=( 2818438 6808230 23 ) utm=0 stm=0 core=1 HZ=100
  | stack=0xa4035000-0xa4037000 stackSize=1036KB
  | held mutexes=
  native: pc 000000000003a0ac  /system/lib/libc.so (__epoll_pwait+20)
  native: pc 0000000000011483  /system/lib/libc.so (epoll_pwait+26)
  native: pc 0000000000011491  /system/lib/libc.so (epoll_wait+6)
  native: pc 0000000000010edf  /system/lib/libutils.so (_ZN7android6Looper9pollInnerEi+98)
  native: pc 0000000000011109  /system/lib/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv+92)
  native: pc 000000000007e371  /system/lib/libandroid_runtime.so (_ZN7android18NativeMessageQueue8pollOnceEP7_JNIEnvi+22)
  native: pc 000000000010e76b  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+102)
  at android.os.MessageQueue.nativePollOnce (Native method)
  at android.os.MessageQueue.next (MessageQueue.java:143)
  at android.os.Looper.loop (Looper.java:122)
  at android.os.HandlerThread.run (HandlerThread.java:61)
"Heap thread pool worker thread 1" tid=2 Native 
"Heap thread pool worker thread 1" prio=5 tid=2 Native (still starting up)
  | group="" sCount=1 dsCount=0 obj=0x0 self=0xb8337008
  | sysTid=23060 nice=0 cgrp=default sched=0/0 handle=0xb81c1910
  | state=S schedstat=( 2796719 5468959 19 ) utm=0 stm=0 core=0 HZ=100
  | stack=0xb49ce000-0xb49d0000 stackSize=1020KB
  | held mutexes=
  native: pc 000000000000f9b0  /system/lib/libc.so (syscall+28)
  native: pc 00000000000a8c4b  /system/lib/libart.so (_ZN3art17ConditionVariable4WaitEPNS_6ThreadE+82)
  native: pc 000000000022f877  /system/lib/libart.so (_ZN3art10ThreadPool7GetTaskEPNS_6ThreadE+50)
  native: pc 000000000022f81f  /system/lib/libart.so (_ZN3art16ThreadPoolWorker3RunEv+54)
  native: pc 000000000023005d  /system/lib/libart.so (_ZN3art16ThreadPoolWorker8CallbackEPv+52)
  native: pc 00000000000132bb  /system/lib/libc.so (_ZL15__pthread_startPv+30)
  native: pc 00000000000111e7  /system/lib/libc.so (__start_thread+6)
"Heap thread pool worker thread 2" tid=3 Native 
"Heap thread pool worker thread 2" prio=5 tid=3 Native (still starting up)
  | group="" sCount=1 dsCount=0 obj=0x0 self=0xb81c0ea0
  | sysTid=23061 nice=0 cgrp=default sched=0/0 handle=0xb833a0b0
  | state=S schedstat=( 5997967 2723698 18 ) utm=0 stm=0 core=0 HZ=100
  | stack=0xb48ce000-0xb48d0000 stackSize=1020KB
  | held mutexes=
  native: pc 000000000000f9b0  /system/lib/libc.so (syscall+28)
  native: pc 00000000000a8c4b  /system/lib/libart.so (_ZN3art17ConditionVariable4WaitEPNS_6ThreadE+82)
  native: pc 000000000022f877  /system/lib/libart.so (_ZN3art10ThreadPool7GetTaskEPNS_6ThreadE+50)
  native: pc 000000000022f81f  /system/lib/libart.so (_ZN3art16ThreadPoolWorker3RunEv+54)
  native: pc 000000000023005d  /system/lib/libart.so (_ZN3art16ThreadPoolWorker8CallbackEPv+52)
  native: pc 00000000000132bb  /system/lib/libc.so (_ZL15__pthread_startPv+30)
  native: pc 00000000000111e7  /system/lib/libc.so (__start_thread+6)
"Heap thread pool worker thread 0" tid=4 Native 
"Heap thread pool worker thread 0" prio=5 tid=4 Native (still starting up)
  | group="" sCount=1 dsCount=0 obj=0x0 self=0xb83390c0
  | sysTid=23059 nice=0 cgrp=default sched=0/0 handle=0xb82a4b58
  | state=S schedstat=( 3379426 4137085 15 ) utm=0 stm=0 core=1 HZ=100
  | stack=0xb4ace000-0xb4ad0000 stackSize=1020KB
  | held mutexes=
  native: pc 000000000000f9b0  /system/lib/libc.so (syscall+28)
  native: pc 00000000000a8c4b  /system/lib/libart.so (_ZN3art17ConditionVariable4WaitEPNS_6ThreadE+82)
  native: pc 000000000022f877  /system/lib/libart.so (_ZN3art10ThreadPool7GetTaskEPNS_6ThreadE+50)
  native: pc 000000000022f81f  /system/lib/libart.so (_ZN3art16ThreadPoolWorker3RunEv+54)
  native: pc 000000000023005d  /system/lib/libart.so (_ZN3art16ThreadPoolWorker8CallbackEPv+52)
  native: pc 00000000000132bb  /system/lib/libc.so (_ZL15__pthread_startPv+30)
  native: pc 00000000000111e7  /system/lib/libc.so (__start_thread+6)
"HeapTrimmerDaemon" tid=6 Waiting 
"HeapTrimmerDaemon" daemon prio=5 tid=6 Waiting
  | group="system" sCount=1 dsCount=0 obj=0x12c061c0 self=0xb833c230
  | sysTid=23066 nice=0 cgrp=default sched=0/0 handle=0xb833ca20
  | state=S schedstat=( 16039218 18453438 23 ) utm=1 stm=0 core=3 HZ=100
  | stack=0xa6f4e000-0xa6f50000 stackSize=1036KB
  | held mutexes=
  at java.lang.Object.wait! (Native method)
- waiting on <0x1c7546fb> (a java.lang.Daemons$HeapTrimmerDaemon)
  at java.lang.Daemons$HeapTrimmerDaemon.run (Daemons.java:311)
- locked <0x1c7546fb> (a java.lang.Daemons$HeapTrimmerDaemon)
  at java.lang.Thread.run (Thread.java:818)
"GCDaemon" tid=7 Waiting 
"FinalizerWatchdogDaemon" tid=8 Waiting 
"Binder_1" tid=9 Native 
"FinalizerDaemon" tid=10 Waiting 
"ReferenceQueueDaemon" tid=11 Waiting 
"Binder_2" tid=12 Native 
"AsyncTask #1" tid=13 Waiting 
"Timer-0" tid=14 Waiting 
"RenderThread" tid=15 Native 
"AsyncTask #2" tid=18 Waiting 
"AsyncTask #3" tid=19 Waiting 
"AsyncTask #4" tid=20 Waiting 
"Binder_3" tid=23 Native 
"AdWorker(Default) #1" tid=24 TimedWaiting 
"java.lang.ProcessManager" tid=25 Waiting 
"AdWorker(Default) #2" tid=26 TimedWaiting 
"AdWorker(Default) #3" tid=27 TimedWaiting 
"AdWorker(Default) #4" tid=28 TimedWaiting 
"AdWorker(Default) #5" tid=29 TimedWaiting 
"Binder_6" tid=30 Native 
"Binder_4" tid=40 Native 
"Binder_7" tid=45 Native 
"Binder_5" tid=49 Native 
"Signal Catcher" tid=5 Runnable 
"Signal Catcher" daemon prio=5 tid=5 Runnable
  | group="system" sCount=0 dsCount=0 obj=0x12c000a0 self=0xb833abf8
  | sysTid=23062 nice=0 cgrp=default sched=0/0 handle=0xb8339498
  | state=R schedstat=( 166092660 21972502 124 ) utm=8 stm=8 core=0 HZ=100
  | stack=0xb47c4000-0xb47c6000 stackSize=1012KB
  | held mutexes= "thread list lock" "mutator lock"(exclusive held)
  native: pc 0000000000004758  /system/lib/libbacktrace_libc++.so (_ZN13UnwindCurrent6UnwindEjP8ucontext+23)
  native: pc 0000000000002f8d  /system/lib/libbacktrace_libc++.so (_ZN9Backtrace6UnwindEjP8ucontext+8)
  native: pc 00000000002411c9  /system/lib/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiPKcPNS_6mirror9ArtMethodE+68)
  native: pc 0000000000225591  /system/lib/libart.so (_ZNK3art6Thread4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+148)
  native: pc 000000000022e8bb  /system/lib/libart.so (_ZN3art10ThreadList14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+142)
  native: pc 0000000000215ca5  /system/lib/libart.so (_ZN3art7Runtime14DumpForSigQuitERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+68)
  native: pc 000000000021a431  /system/lib/libart.so (_ZN3art13SignalCatcher13HandleSigQuitEv+752)
  native: pc 000000000021aadb  /system/lib/libart.so (_ZN3art13SignalCatcher3RunEPv+318)
  native: pc 00000000000132bb  /system/lib/libc.so (_ZL15__pthread_startPv+30)
  native: pc 00000000000111e7  /system/lib/libc.so (__start_thread+6)

很好的输入。我看到了我的错误。我没有想到直接从doinbackground返回数据并在UI中使用是不安全的。让我重新表述一下你说的话,因为我不确定我是否理解了处理程序和弱引用的术语。frag调用异步任务,该任务调用http(在doinbackgroud中),当它获取ip时,它等待onpostexecute发送ip @通过一个方法? - narb
即使onPostExecute(...)在UI线程上触发,它也不应直接触摸任何视图,因为这很容易导致内存泄漏。您应该做的是向View的所有者(例如Fragment或Activity)指示某些工作已完成,并且应使用AsyncTask数据更新其视图。我建议使用Handler在AsyncTask之间传递数据,并将其包装在WeakReference中,以便如果Fragment或Activity被销毁,则不会对其产生强引用,从而防止泄漏活动。 - cincy_anddeveloper
我猜你无法重现ANR的原因是doInBackground方法完成得太快了。尝试在该方法中加入一个sleep调用。或者只需将下载代码放置在for循环中并执行几次即可。为了保持清醒,记录一下执行doInBackground所需的时间... 我猜对于你在现场的用户来说,他们的网络条件要差得多,下载时间会显著增加。 - cincy_anddeveloper
我真的不明白为什么我们需要异步任务 ;) - narb
AsyncTask 是在后台线程上执行一些长时间运行的操作并定期使用有关数据的信息更新应用程序 UI 的绝妙方式。有趣的是,如果您不特别注意,它很容易导致内存泄漏,但这对于 Android/Java 和 C++ 中的许多其他事情也是如此 :) 要正确执行此操作需要一点思考。祝好运! - cincy_anddeveloper
闻起来很香。尽管在同一个例程中我正在执行一个异步任务,它昨天仍然从doinbackground直接返回一个字符串并崩溃了:):) 再一次:非常感谢! - narb
1个回答

9
我认为你的问题是在调用GetIP_WAN().execute()后立即调用AsyncTask.get()。我假设你正在UI线程上调用GetIP_WAN().execute()。如果它在onClick回调或BroadcastReceiver中,则肯定是这样的。因此,我认为正在发生的情况是你的GetIP_WAN任务正在正确地在后台线程上执行,但get()调用正在尝试检索将从doInBackground()返回的数据。但是,在doInBackground和可能的onPostExecute(...)返回之前,该调用(get())将永远不会返回,从而导致在UI线程上阻塞。如果您阅读AsyncTask类内的get文档,则会发现:

/** * 等待计算完成,然后检索其结果。 * * @return 计算结果。 * * @throws CancellationException 如果计算被取消。 * @throws ExecutionException 如果计算抛出异常。 * @throws InterruptedException 如果等待时当前线程被中断。 */

具有讽刺意味的是,您正在否定AsnycTask的目的。即使工作在后台线程上进行,也会强制UI线程等待工作完成,然后才能完成UI线程上的任何其他处理。当Android OS检测到UI / Main线程已经阻塞5秒钟时,它会处理创建ANR对话框。

我假设你调用get以便从GetIP_WAN获取数据,以便在UI线程上操作/显示它。我建议的是,你将某种形式的引用传递到拥有的activity或fragment中,并在任务完成并触发onPostExecute(...)时对activity或fragment进行操作以使用doInBackground(...)中下载的数据更新其UI。我推荐的一种模式是将包装在WeakReference中的Handler引用传递到GetIP_WAN中,并在onPostExecute(...)中发送一个空消息,表示工作已完成,可以调用GetIP_WAN.get()。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接