应用在启动时崩溃

3
当我启动我的应用程序时,我启动一个AsyncTask来进行一些下载。这可能需要一段时间。
当该线程正在下载数据时,我已经开始监听位置更新。当我收到新位置时,我会启动一个新的AsyncTask来进行一些处理。但是,这个类依赖于下载的数据,因此它必须等待下载完成:
public void setLocation(Location location) throws IOException {
    Logger.log("New location - calculating nearest stations");
    if (!initialStationsRead) {
        Logger.log("Location update waiting for stations to be read");
        while (!initialStationsRead)
            ;
        Logger.log("Location update done waiting");
    }
    /* Do the processing */
}

第一个线程完成后,将initialStationsRead设置为true,因此第二个线程可以在此之后接手。在我的测试设备上,这一切都运作正常。

然而,我收到了一封来自用户的电子邮件,告诉我该应用无法启动。加载屏幕出现后,10-12秒后消失而没有警告。他使用的是HTC One S。

以下是他发送给我的logcat:

07-05 22:11:04.938: W/dalvikvm(19961): threadid=2: spin on suspend #2 threadid=11 (pcf=1)
07-05 22:11:04.938: I/dalvikvm(19961): "GC" daemon prio=5 tid=2 RUNNABLE
07-05 22:11:04.938: I/dalvikvm(19961):   | group="system" sCount=0 dsCount=0 obj=0x40d5c580 self=0x1669ae8
07-05 22:11:04.938: I/dalvikvm(19961):   | sysTid=19965 nice=0 sched=0/0 cgrp=default handle=21931384
07-05 22:11:04.938: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=2 stm=0 core=1
07-05 22:11:04.938: I/dalvikvm(19961):   at dalvik.system.NativeStart.run(Native Method)
07-05 22:11:04.938: I/dalvikvm(19961): "AsyncTask #3" prio=5 tid=11 RUNNABLE JIT
07-05 22:11:04.938: I/dalvikvm(19961):   | group="main" sCount=1 dsCount=0 obj=0x40f90588 self=0x1b35b00
07-05 22:11:04.938: I/dalvikvm(19961):   | sysTid=19991 nice=0 sched=0/0 cgrp=default handle=29193008
07-05 22:11:04.938: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=287 stm=1 core=1
07-05 22:11:04.938: I/dalvikvm(19961):   at com.busybits.treinverkeer.data.Data.setLocation(Data.java:~102)
07-05 22:11:04.938: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:408)
07-05 22:11:04.938: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:1)
07-05 22:11:04.938: I/dalvikvm(19961):   at android.os.AsyncTask$2.call(AsyncTask.java:264)
07-05 22:11:04.938: I/dalvikvm(19961):   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-05 22:11:04.938: I/dalvikvm(19961):   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-05 22:11:04.938: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-05 22:11:04.938: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-05 22:11:04.938: I/dalvikvm(19961):   at java.lang.Thread.run(Thread.java:864)
07-05 22:11:05.629: D/WifiStateMachine(436): fetchRssiAndLinkSpeedNative RSSI = -32
07-05 22:11:05.689: W/dalvikvm(19961): threadid=2: spin on suspend #3 threadid=11 (pcf=1)
07-05 22:11:05.689: I/dalvikvm(19961): "GC" daemon prio=5 tid=2 RUNNABLE
07-05 22:11:05.689: I/dalvikvm(19961):   | group="system" sCount=0 dsCount=0 obj=0x40d5c580 self=0x1669ae8
07-05 22:11:05.689: I/dalvikvm(19961):   | sysTid=19965 nice=0 sched=0/0 cgrp=default handle=21931384
07-05 22:11:05.689: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=2 stm=0 core=1
07-05 22:11:05.689: I/dalvikvm(19961):   at dalvik.system.NativeStart.run(Native Method)
07-05 22:11:05.689: I/dalvikvm(19961): "AsyncTask #3" prio=5 tid=11 RUNNABLE JIT
07-05 22:11:05.689: I/dalvikvm(19961):   | group="main" sCount=1 dsCount=0 obj=0x40f90588 self=0x1b35b00
07-05 22:11:05.689: I/dalvikvm(19961):   | sysTid=19991 nice=0 sched=0/0 cgrp=default handle=29193008
07-05 22:11:05.689: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=362 stm=1 core=1
07-05 22:11:05.689: I/dalvikvm(19961):   at com.busybits.treinverkeer.data.Data.setLocation(Data.java:~102)
07-05 22:11:05.689: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:408)
07-05 22:11:05.689: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:1)
07-05 22:11:05.689: I/dalvikvm(19961):   at android.os.AsyncTask$2.call(AsyncTask.java:264)
07-05 22:11:05.689: I/dalvikvm(19961):   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-05 22:11:05.689: I/dalvikvm(19961):   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-05 22:11:05.689: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-05 22:11:05.689: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-05 22:11:05.689: I/dalvikvm(19961):   at java.lang.Thread.run(Thread.java:864)
07-05 22:11:05.719: D/skia(1004): AndroidImageRef[ 0x2438190 ] releasePixel fail as lockCount=1
07-05 22:11:06.439: W/dalvikvm(19961): threadid=2: spin on suspend #4 threadid=11 (pcf=1)
07-05 22:11:06.439: I/dalvikvm(19961): "GC" daemon prio=5 tid=2 RUNNABLE
07-05 22:11:06.439: I/dalvikvm(19961):   | group="system" sCount=0 dsCount=0 obj=0x40d5c580 self=0x1669ae8
07-05 22:11:06.439: I/dalvikvm(19961):   | sysTid=19965 nice=0 sched=0/0 cgrp=default handle=21931384
07-05 22:11:06.439: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=2 stm=0 core=1
07-05 22:11:06.439: I/dalvikvm(19961):   at dalvik.system.NativeStart.run(Native Method)
07-05 22:11:06.439: I/dalvikvm(19961): "AsyncTask #3" prio=5 tid=11 RUNNABLE JIT
07-05 22:11:06.439: I/dalvikvm(19961):   | group="main" sCount=1 dsCount=0 obj=0x40f90588 self=0x1b35b00
07-05 22:11:06.439: I/dalvikvm(19961):   | sysTid=19991 nice=0 sched=0/0 cgrp=default handle=29193008
07-05 22:11:06.439: I/dalvikvm(19961):   | schedstat=( 0 0 0 ) utm=437 stm=1 core=1
07-05 22:11:06.439: I/dalvikvm(19961):   at com.busybits.treinverkeer.data.Data.setLocation(Data.java:~102)
07-05 22:11:06.439: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:408)
07-05 22:11:06.439: I/dalvikvm(19961):   at com.busybits.treinverkeer.TreinVerkeer$SetLocationAsyncTask.doInBackground(TreinVerkeer.java:1)
07-05 22:11:06.439: I/dalvikvm(19961):   at android.os.AsyncTask$2.call(AsyncTask.java:264)
07-05 22:11:06.439: I/dalvikvm(19961):   at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
07-05 22:11:06.439: I/dalvikvm(19961):   at java.util.concurrent.FutureTask.run(FutureTask.java:137)
07-05 22:11:06.439: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
07-05 22:11:06.439: I/dalvikvm(19961):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
07-05 22:11:06.439: I/dalvikvm(19961):   at java.lang.Thread.run(Thread.java:864)

这段代码重复了x次。

现在,Data.java:102while(!initialStationsRead)这一行,所以肯定出了问题。

出了什么问题,我该怎么解决?


2
不要阻塞setLocation()方法直到位置数据可用,可以尝试在下载完成且有位置可用后开始处理数据的处理,或者在数据下载完成后注册您的位置更新。 - Jan-Henk
可以在异步任务中使用 Handler 处理消息,例如下载数据,通过 Handler 将其传递到异步任务中... - t0mm13b
我已经向用户发送了带有@Jan-Henk建议的版本,现在我只需要等待看看这是否解决了问题。不过,你有什么想法为什么这会发生在他的设备上而不是我的或其他人的设备上呢? - nhaarman
我现在只是猜测,但也许用户设备上有很多位置更新,这将导致很多阻塞的方法,进而导致了这个问题? - Jan-Henk
从他发给我的logcat中,我可以得出结论这并不是情况 :) - nhaarman
显示剩余2条评论
2个回答

3
第一个线程在完成时将initialStationsRead设置为true,以便第二个线程可以在此之后继续执行。
繁忙循环非常不好。如果我手边有圣水,你现在可能会被淋得湿透。
(这也意味着我对长距离的圣水投掷有很好的准头,这可能并不是事实)
Java有很多线程同步选项,已经有了十年以上的历史,从底层的Object上的wait()和notify()到java.util.concurrent结构,如Semaphore。选择其中一种并使用它,摆脱繁忙的循环。
或者,按照Jan-Henk的建议,在同一个线程上基于标志逐个完成工作。
任何想法吗,为什么这会在他的设备上发生,而不是在我的设备或其他人我所知道的设备上?
首先,One S是双核的,所以你的线程实际上可能同时运行(每个核一个)。线程问题更容易在多核环境中浮出水面。
此外,Angelo的回答 - 在我写这篇文章时发布 - 值得注意。

其实,我这里可以用点水,天气热得要命 :) 无论如何,就像我在我的问题中评论的那样,我已经实现了Jan-Henk的建议并将副本发送给了用户。虽然解释很好,但还是要点个赞!在接受答案之前,我会等待用户的回复。 - nhaarman

0

我不知道这是否有帮助,但请记住,在HoneyCombAndroid 3.0)之后,在DonutAndroid 1.6)之前,只能同时运行一个AsyncTask,因为AsyncTask使用线程池模式,并且这些版本的默认线程池大小为1。如果您想要在这些版本的Android中同时运行您正在使用的AsyncTasks,则可以使用此代码executeOnExecutor(Executor, Params...),并使用标志THREAD_POOL_EXECUTOR。有关更多信息,请参见此先前帖子的答案。考虑到用户拥有运行Android 4.0HTC One S设备,也许这是您问题的根源。


请注意,仅当您的android:targetSdkVersion设置为13或更高版本,并且您正在运行Android 3.2或更高版本时,才会针对execute()使用序列化的执行程序。 - CommonsWare
我确实已经解决了那个问题,并且已经应用了THREAD_POOL_EXECUTOR修复程序。(请参见此问题:http://stackoverflow.com/questions/11229734/disable-use-of-asynctask-using-custom-asynctask)感谢您的思考! - nhaarman
我提出了一个解决方案来回答你之前的问题。我不知道这是否是你所寻找的。希望能有所帮助 :) - AggelosK

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