安卓:有CalledFromWrongThreadException在onPostExecute() - 这怎么可能呢? [英] Android: got CalledFromWrongThreadException in onPostExecute() - How could it be?

查看:133
本文介绍了安卓:有CalledFromWrongThreadException在onPostExecute() - 这怎么可能呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在生产的几个星期,使用ACRA一个应用程序,我不得不零失误,直到有奇怪的错误今天报道。

I have an app in production for a few weeks, using ACRA, and I had zero errors until one strange error reported today.

我有:

    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

这是这个方法的堆栈跟踪未来(回抽):

coming from this method in the stack trace (retraced):

at my.app.CountdownFragment$1.void onPostExecute(java.lang.Object)(SourceFile:1)

这是相关的源代码片段:

And this is the relevant source snippet:

    private void addInstructionsIfNeeded() {
    if (S.sDisplayAssist) {
        new AsyncTask<String, Void, String>() {

            @Override
            protected String doInBackground(String... params) {
                return null;
            }

            /*
             * runs on the ui thread
             */
            protected void onPostExecute(String result) {

                Activity a = getActivity();

                if (S.sHelpEnabled && a != null) {

                    in = new InstructionsView(a.getApplicationContext());

                    RelativeLayout mv = (RelativeLayout) a
                            .findViewById(R.id.main_place);

                    mv.addView(in.prepareView());
                }

            };

        }.execute("");
    }
}

其中, addInstructionsIfNeeded()被称为从处理程序分派消息(用户界面THEAD)。

Where addInstructionsIfNeeded() is called from a handler dispatched message (the UI thead).

  • onPostExecute()运行在UI线程上,那么为什么我有错线?
  • 这code已经跑了超过150个设备,以及超过10万次(根据乱舞),和从未有过这种错误。
  • 在始发设备是三星SGH-I997运行SDK 4.0.4
  • onPostExecute() runs on the UI thread, so why I've got "wrong thread"?
  • This code ran already on more than 150 devices, and more than 100000 times (according to Flurry), and never had this error.
  • The originating device is Samsung SGH-I997 running SDK 4.0.4

我的问题是:这怎么可能

My question is: How could it be?

修改: 这一切都发生在一个片段

EDIT: This all happens in a fragment

推荐答案

我是从同一个问题的痛苦,这是另一个Android框架的错误...

i was suffering from the same problem, this is another android framework bug...

发生了什么:

在某些情况下,应用程序可以有一个以上的活套,因此一个以上的UI线程

in certain circumstances an application can have more than one "looper" and therefore more than one "UI thread"

- 侧面说明 - 我使用的宽松感的术语UI线程这个答案,因为当人们说UI线程他们通常是指主或进入线程,的Andr​​oid像许多其他操作系统之前,允许多个消息泵(称为尺蠖在Android中,看到: http://en.wikipedia.org/wiki/Event_loop )针对不同的用户界面的树,这样机器人对所有意图和目的是能够运行一个以上的,在UI线程某些情况下,用这个词引起歧义横行... - 端侧注 -

--side note-- i am using the term "UI thread" in the loosest of senses in this answer, since when people say "UI thread" they usually mean main or entry thread, Android like many of other OS before it, allow for for multiple message pumps (called a Looper in Android, see: http://en.wikipedia.org/wiki/Event_loop) for different UI trees, as such android for all intents and purposes is capable of running more than one "UI thread" in certain circumstances and using that term leads to rampant ambiguities... --end side note--

这意味着:

因为一个应用程序可以有多个UI线程和的AsyncTask 总是<一个在UI线程上运行 href="http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute%28Result%29">[ref],有人决定[不良]认为代替AsyncTask的它创建线程始终运行(这情况下是正确的UI线程的99.999999%),他们决定用骗人pocus(或制作不良的快捷方式,你决定)来执行在主尺蠖。

since an application can have more than one "UI thread" and an AsyncTask always "Runs on the UI thread" [ref], someone decided [poorly] that instead of the AsyncTask always running on its creation thread (which in 99.999999% of cases would be the correct "UI thread") they decided to use hocus pocus (or a poorly crafted shortcut, you decide) to execute on the "main looper"..

例如:

    Log.i("AsyncTask / Handler created ON: " + Thread.currentThread().getId());
    Log.i("Main Looper: " + Looper.getMainLooper().getThread().getId() + "      myLooper: "+ Looper.myLooper().getThread().getId());

    new AsyncTask<Void, Void, Void>() {

        @Override
        protected Void doInBackground(Void... params) {
            Log.i("doInBackground ran ON: " + Thread.currentThread().getId());
            // I'm in the background, all is normal

            handler.post(new Runnable() {

                @Override
                public void run() {
                    Log.i("Handler posted runnable ON: " + Thread.currentThread().getId());
                    // this is the correct thread, that onPostExecute should be on
                }
            });

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            Log.i("onPostExecute ran ON: " + Thread.currentThread().getId());
            // this CAN be the wrong thread in certain situations
        }

    }.execute();

如果调用从上面的输出中所描述的糟糕的情况会是这个样子:

    AsyncTask / Handler created ON: 16
    Main Looper: 1      myLooper: 16
    doInBackground ran ON: 12
    onPostExecute ran ON: 1
    Handler posted runnable ON: 16

这是一个巨大的失败的AsyncTask

如图所示这可以使用就可以减轻的 Handler.post(可运行)在我的特定情况下,我的UI线程的情况下的二元性是由以下事实引起的我在的WebView 有了自己的:是为响应从的WebView ,基本上是所谓的JavaScript接口方法创建对话框UI线程,这是我目前对..

as shown this can be mitigated using a Handler.post(Runnable) in my specific case the duality of my "UI thread" situation was caused by the fact that I was creating a dialog in response to a JavaScript interface method called from a WebView, basically: the WebView had its own "UI thread" and that was the one that i was currently running on..

这是我可以告诉(不真正关心或读入太多)似乎在总体运行的AsyncTask 类的回调方法是落单的静态实例处理程序(请参见:<一href="http://grep$c$c.com/file/repository.grep$c$c.com/java/ext/com.google.android/android/4.0.3_r1/android/os/AsyncTask.java#AsyncTask.0sHandler">http://grep$c$c.com/file/repository.grep$c$c.com/java/ext/com.google.android/android/4.0.3_r1/android/os/AsyncTask.java#AsyncTask.0sHandler),这意味着它总是将主线程或项线,他们错误地称之为UI线程(这是psumed任何线索,其中UI交互发生,如$ P $上执行。多在这种情况下,线程),这是既粗制滥造的工艺,并从Android团队...弱酱以次充好文档,酱油弱

from what i can tell (without really caring about or reading into it too much) it seems that the AsyncTask class' callback methods in general run off a single statically instantiated handler (see: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.3_r1/android/os/AsyncTask.java#AsyncTask.0sHandler), which means that it is always going to execute on the "main thread" or "entry thread" which they incorrectly refer to as the "UI thread" (which is presumed as any thread where UI interactions take place, eg. multiple threads in this case) this is both shoddy craftsmanship and shoddy documentation from the android team... weak sauce, the sauce is weak

希望这可以帮助你-ck

hope this helps you -ck

这篇关于安卓:有CalledFromWrongThreadException在onPostExecute() - 这怎么可能呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆