CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触视图

Posted

技术标签:

【中文标题】CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触视图【英文标题】:CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch views 【发布时间】:2011-03-17 20:18:47 【问题描述】:

我在 android 中遇到以下错误:

CalledFromWrongThreadException;: 仅限 创建一个的原始线程 视图层次结构可以触及它的视图

当我尝试在我的 Activity 中更新 Textview 时似乎会发生这种情况,更新 TextView 的调用来自我的 Activity 但我仍然收到上述错误。

我是这样的:

onCreate() - 设置按钮和文本视图。

onStateChange() - 状态更改通知的侦听器,当它在 TextView 更改为说一些不同的文本时收到通知。

当我收到新文本的通知时,我尝试将 TextView 更改为:

((TextView)findViewById(R.id.title)).setText("Some Text");

但我得到了上述错误。

通过谷歌搜索,看来我应该使用处理程序来更改 TextView 或者使用 AsyncTask?

谁能解释一下哪个更好用?为什么?

编辑:添加代码片段:


     public void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);

            requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);  

            setContentView(R.layout.my);

            getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.my_title);  

            ((TextView)findViewById(R.id.time)).setText("Hello Text");


            findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() 
                public void onClick(View v) 

                    Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"));
                    startActivity(dialIntent);

                        dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,KeyEvent.FLAG_SOFT_KEYBOARD));
                        dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));       
                
        );

     

//CallBacks from running Service

private final ICallDialogActivity.Stub iCallDialogActivity = new ICallDialogActivity.Stub()

@Override
public void onStateChanged(int callState)
                throws RemoteException     
            switch(callState)
            case GlobalData.CALL_STATUS_IDLE:

                break;

            case GlobalData.CALL_STATUS_DISCONNECTING:
                byeSetup();
                break;
     

;

public void byeSetup()

            ((TextView)findViewById(R.id.time)).setText("Bye Text");

            findViewById(R.id.keyboardimage).setOnClickListener(new OnClickListener() 
                public void onClick(View v) 
                    //Void the Button
                );

【问题讨论】:

你在子类中吗? onStateChange 在哪里被覆盖? 嗨 Pentium10,它通过 AIDL 接口被覆盖并与服务通信,服务将收到一些更改的通知,然后将告诉 Activity 基于此更新其 TextView。我添加了代码 sn-ps 以更好地演示我正在尝试的内容,该错误似乎非常随机出现,并且在 Activity 处于前台和不在前台时都会出现。 CalledFromWrongThreadException 的可能重复项 【参考方案1】:

看起来你在错误的线程上。尝试使用处理程序在正确的线程上更新 GUI。请参阅来自 android.com 的 Handling Expensive Operations in the UI Thread 示例。基本上,您会将byeSetup 包装在Runnable 中并使用Handler 实例调用它。

Handler refresh = new Handler(Looper.getMainLooper());
refresh.post(new Runnable() 
    public void run()
    
        byeSetup();
    
);

【讨论】:

看来我不必杀了我。 我觉得 Keshav 的回答比较好。 这比使用runOnUiThread() 更好吗?我可以看到我们不需要对 Activity 的引用。此解决方案还有其他优点吗?【参考方案2】:

当更改涉及到主线程(UiThread)时。在另一个线程中使用它来更改任何视图。

runOnUiThread(new Runnable() 
    @Override
    public void run() 

      // TODO your Code 
        et_Pass.setText("");
    
);

【讨论】:

这应该是可以接受的答案,如果你使用的是Fragment,你可以通过getActivity.runOnUiThread()调用这个方法......【参考方案3】:

为了清晰和实施,扩展 willcodejavaforfood 的答案...

我得到了这个工作,下面是我是如何做到的。我在 Service 中运行多个处理线程,因此在 Activity 中运行的其他解决方案不起作用,例如 runOnUiThread(new Runnable() ...

把它放在你的服务类的顶部,以便在这个类的任何地方都可以访问它:

Handler handler;

把它放在你的服务类的 onCreate 方法或加载到服务主线程上的东西中

handler= new Handler(Looper.getMainLooper());

将其放入您的附加线程中以“回发”代码以在 UI 或服务 UI(无论其名称如何)中运行:

handler.post(new Runnable() 
    public void run() 
        playNext(); //or whatever method you want to call thats currently not working
    
);

【讨论】:

【参考方案4】:

对于其他人,只需替换 byeSetup();使用您的代码语句或方法。 byeSetup() 是一个示例方法。希望它会节省您的一些时间。

【讨论】:

【参考方案5】:

另一种方法,这次使用android.os.Message

android.os.Handler 定义为活动中的字段:

private final Handler myTextHandler = new Handler(new Handler.Callback() 
    @Override
    public boolean handleMessage(Message stringMessage) 
        textView.append((String) stringMessage.obj);
        return true;
    
);

然后像这样从您的其他线程中提供它:

Message stringMessage = Message.obtain(myTextHandler);
stringMessage.obj = "Hello!";
stringMessage.sendToTarget();

【讨论】:

【参考方案6】:

您可以使用视图的内置 post 方法来更新其他线程中的内容,就像我在 kotlin 中使用编辑文本一样。

address_box.post  address_box.text="my text"

【讨论】:

以上是关于CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触视图的主要内容,如果未能解决你的问题,请参考以下文章